Created
January 28, 2019 21:30
-
-
Save lukasreuter/083ad923c1ed17080188a8edac7e1722 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using Assets.Scripts; | |
using UnityEngine; | |
using Valve.VR; | |
namespace Assets { | |
public class Portal : MonoBehaviour { | |
private static readonly Dictionary<StereoTargetEyeMask, Rect> Viewports = new Dictionary<StereoTargetEyeMask, Rect> { | |
{ StereoTargetEyeMask.None, new Rect(0, 0, 1, 1) }, | |
{ StereoTargetEyeMask.Left, new Rect(0, 0, .5f, 1) }, | |
{ StereoTargetEyeMask.Right, new Rect(.5f, 0, .5f, 1) }, | |
{ StereoTargetEyeMask.Both, new Rect(0, 0, 1, 1) } | |
}; | |
private static Lock Lock = new Lock(false); | |
public Transform Destination; | |
public Camera PlayerCamera; | |
private new Camera camera; | |
public void Start() { | |
var texture = new RenderTexture(2048, 2048, 24); | |
if (PlayerCamera.stereoEnabled) texture.width *= 2; | |
texture.antiAliasing = Mathf.Max(1, QualitySettings.antiAliasing); | |
var cameraObject = new GameObject(name + " Camera"); | |
cameraObject.transform.parent = transform.parent; | |
camera = cameraObject.SummonComponent<Camera>(); | |
camera.enabled = false; | |
camera.clearFlags = PlayerCamera.clearFlags; | |
camera.backgroundColor = PlayerCamera.backgroundColor; | |
camera.farClipPlane = PlayerCamera.farClipPlane; | |
camera.nearClipPlane = PlayerCamera.nearClipPlane; | |
camera.orthographic = PlayerCamera.orthographic; | |
camera.fieldOfView = PlayerCamera.fieldOfView; | |
camera.aspect = PlayerCamera.aspect; | |
camera.orthographicSize = PlayerCamera.orthographicSize; | |
camera.targetTexture = texture; | |
camera.cullingMask &= ~(1 << LayerMask.NameToLayer("Portal")); | |
if (camera.clearFlags == CameraClearFlags.Skybox) { | |
var skybox = cameraObject.SummonComponent<Skybox>(); | |
skybox.enabled = true; | |
skybox.material = PlayerCamera.SummonComponent<Skybox>().material; | |
} | |
var propertyBlock = new MaterialPropertyBlock(); | |
propertyBlock.SetTexture("_PortalTexture", texture); | |
var renderers = GetComponentsInChildren<Renderer>(); | |
foreach (var renderer in renderers) { | |
renderer.sharedMaterial = new Material(Shader.Find("Custom/Portal")); | |
renderer.SetPropertyBlock(propertyBlock); | |
} | |
} | |
public void OnCollisionStay(Collision collision) { | |
if (collision.gameObject.GetComponent<Camera>() == PlayerCamera) { | |
transform.FindChild("Back").gameObject.SetActive(true); | |
transform.FindChild("Top").gameObject.SetActive(true); | |
transform.FindChild("Bottom").gameObject.SetActive(true); | |
transform.FindChild("Left").gameObject.SetActive(true); | |
transform.FindChild("Right").gameObject.SetActive(true); | |
} | |
} | |
public void OnCollisionExit(Collision collision) { | |
if (collision.gameObject.GetComponent<Camera>() == PlayerCamera) { | |
transform.FindChild("Back").gameObject.SetActive(false); | |
transform.FindChild("Top").gameObject.SetActive(false); | |
transform.FindChild("Bottom").gameObject.SetActive(false); | |
transform.FindChild("Left").gameObject.SetActive(false); | |
transform.FindChild("Right").gameObject.SetActive(false); | |
PlayerCamera.transform.parent.position += Destination.position - transform.position; | |
} | |
} | |
public void OnWillRenderObject() { | |
if (Lock.Engaged || Camera.current != PlayerCamera || !camera.isActiveAndEnabled) { | |
return; | |
} | |
using (Lock = new Lock()) { | |
if (!PlayerCamera.stereoEnabled || camera.stereoTargetEye == StereoTargetEyeMask.None) { | |
RenderCamera(PlayerCamera.transform.position, PlayerCamera.transform.rotation, PlayerCamera.projectionMatrix, Viewports[camera.stereoTargetEye]); | |
return; | |
} | |
switch (camera.stereoTargetEye) { | |
case StereoTargetEyeMask.Both: | |
RenderEye(StereoTargetEyeMask.Left); | |
RenderEye(StereoTargetEyeMask.Right); | |
break; | |
default: | |
RenderEye(camera.stereoTargetEye); | |
break; | |
} | |
} | |
} | |
private void RenderEye(StereoTargetEyeMask eye) { | |
var eyeIndex = (int)eye - 1; | |
var eyePos = PlayerCamera.transform.TransformPoint(SteamVR.instance.eyes[eyeIndex].pos); | |
var eyeRot = PlayerCamera.transform.rotation * SteamVR.instance.eyes[eyeIndex].rot; | |
var projectionMatrix = GetSteamVrProjectionMatrix(PlayerCamera, (EVREye)eyeIndex); | |
RenderCamera(eyePos, eyeRot, projectionMatrix, Viewports[eye]); | |
} | |
private void RenderCamera(Vector3 playerPosition, Quaternion playerRotation, Matrix4x4 playerProjectionMatrix, Rect playerViewport) { | |
camera.projectionMatrix = playerProjectionMatrix; | |
camera.rect = playerViewport; | |
var angleSign = Vector3.Cross(Vector3.Scale(transform.forward, Vector3Helper.XZ), Vector3.Scale(Destination.forward, Vector3Helper.XZ)).normalized.y; | |
var relativeAngle = angleSign * Vector2.Angle(new Vector2(transform.forward.x, transform.forward.z), new Vector2(Destination.forward.x, Destination.forward.z)); | |
camera.transform.eulerAngles = playerRotation.eulerAngles + new Vector3(0, relativeAngle, 0); | |
camera.transform.position = Destination.position + Quaternion.Euler(0, relativeAngle, 0) * (playerPosition - transform.position); | |
// TODO: Near plane clipping. | |
camera.Render(); | |
} | |
private static Matrix4x4 GetSteamVrProjectionMatrix(Camera cam, EVREye eye) { | |
var proj = SteamVR.instance.hmd.GetProjectionMatrix(eye, cam.nearClipPlane, cam.farClipPlane, SteamVR.instance.graphicsAPI); | |
return new Matrix4x4 { | |
m00 = proj.m0, | |
m01 = proj.m1, | |
m02 = proj.m2, | |
m03 = proj.m3, | |
m10 = proj.m4, | |
m11 = proj.m5, | |
m12 = proj.m6, | |
m13 = proj.m7, | |
m20 = proj.m8, | |
m21 = proj.m9, | |
m22 = proj.m10, | |
m23 = proj.m11, | |
m30 = proj.m12, | |
m31 = proj.m13, | |
m32 = proj.m14, | |
m33 = proj.m15 | |
}; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Generic; | |
using UnityEngine; | |
namespace Assets.Scripts { | |
public class WorldGenerator : MonoBehaviour { | |
private static readonly Vector3 RoomScale = SteamVRHelper.GetBounds(); | |
public Camera PlayerCamera; | |
public GameObject Portal; | |
public GameObject Room; | |
public Vector3 Size = new Vector3(3, 3, 3); | |
public void Start() { | |
Portal.GetComponent<Portal>().PlayerCamera = PlayerCamera; | |
Room.transform.FindChild("Walls").transform.localScale = RoomScale; | |
var rooms = new Dictionary<int, Dictionary<int, Dictionary<int, GameObject>>>(); | |
for (var x = 0; x < Size.x; x++) { | |
for (var y = 0; y < Size.y; y++) { | |
for (var z = 0; z < Size.z; z++) { | |
var coordinate = new Vector3(2 * x, 2 * y, 2 * z); | |
var position = Vector3.Scale(RoomScale, coordinate); | |
Room.transform.position = position; | |
var color = new Color(x / Size.x, y / Size.y, z / Size.z); | |
var room = Instantiate(Room); | |
room.name = string.Format("Room ({0}, {1}, {2})", x, y, z); | |
foreach (var wallRenderer in room.transform.FindChild("Walls").GetComponentsInChildren<Renderer>()) { | |
wallRenderer.material = wallRenderer.sharedMaterial; | |
wallRenderer.material.color = color; | |
} | |
var scale = RoomScale; | |
var xOffset = (scale.x - Portal.transform.localScale.x) / 2; | |
var yOffset = scale.y / 2; | |
var zOffset = 0; | |
var portals = room.transform.FindChild("Portals"); | |
var portalOffset = position; | |
var portalScale = Portal.transform.localScale; | |
Portal.transform.localScale = new Vector3(portalScale.x, scale.y, portalScale.z); | |
var portalRotation = 0; | |
Portal.transform.eulerAngles = new Vector3(0, portalRotation, 0); | |
Portal.transform.position = new Vector3(-xOffset, yOffset, -zOffset) + portalOffset; | |
if (x != 0) { | |
var leftPortal = Instantiate(Portal); | |
leftPortal.name = "Left Portal"; | |
leftPortal.transform.parent = portals; | |
} | |
portalRotation += 180; | |
Portal.transform.eulerAngles = new Vector3(0, portalRotation, 0); | |
Portal.transform.position = new Vector3(-xOffset, yOffset, zOffset) + portalOffset; | |
if (x != Size.x - 1) { | |
var rightPortal = Instantiate(Portal); | |
rightPortal.name = "Right Portal"; | |
rightPortal.transform.parent = portals; | |
} | |
Portal.transform.eulerAngles = new Vector3(0, portalRotation, 0); | |
Portal.transform.position = new Vector3(xOffset, yOffset, zOffset) + portalOffset; | |
if (z != Size.z - 1) { | |
var frontPortal = Instantiate(Portal); | |
frontPortal.name = "Front Portal"; | |
frontPortal.transform.parent = portals; | |
} | |
portalRotation += 180; | |
Portal.transform.eulerAngles = new Vector3(0, portalRotation, 0); | |
Portal.transform.position = new Vector3(xOffset, yOffset, -zOffset) + portalOffset; | |
if (z != 0) { | |
var backPortal = Instantiate(Portal); | |
backPortal.name = "Back Portal"; | |
backPortal.transform.parent = portals; | |
} | |
var row = rooms.ContainsKey(x) ? rooms[x] : rooms[x] = new Dictionary<int, Dictionary<int, GameObject>>(); | |
var column = row.ContainsKey(y) ? row[y] : row[y] = new Dictionary<int, GameObject>(); | |
column[z] = room; | |
} | |
} | |
} | |
for (var x = 0; x < Size.x; x++) { | |
for (var y = 0; y < Size.y; y++) { | |
for (var z = 0; z < Size.z; z++) { | |
var portals = rooms[x][y][z].transform.FindChild("Portals"); | |
var leftPortal = portals.FindChild("Left Portal"); | |
var rightPortal = portals.FindChild("Right Portal"); | |
var backPortal = portals.FindChild("Back Portal"); | |
var frontPortal = portals.FindChild("Front Portal"); | |
if (leftPortal != null) { | |
leftPortal.GetComponent<Portal>().Destination = rooms[x - 1][y][z].transform.FindChild("Portals").FindChild("Right Portal"); | |
} | |
if (rightPortal != null) { | |
rightPortal.GetComponent<Portal>().Destination = rooms[x + 1][y][z].transform.FindChild("Portals").FindChild("Left Portal"); | |
} | |
if (backPortal != null) { | |
backPortal.GetComponent<Portal>().Destination = rooms[x][y][z - 1].transform.FindChild("Portals").FindChild("Front Portal"); | |
} | |
if (frontPortal != null) { | |
frontPortal.GetComponent<Portal>().Destination = rooms[x][y][z + 1].transform.FindChild("Portals").FindChild("Back Portal"); | |
} | |
} | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment