public bool ShouldCameraRender(Camera cam, ScreenPoatalArea spa) { var planes = GeometryUtility.CalculateFrustumPlanes(cam); var mySpa = GetPortalRect(cam); float xMin = Mathf.Max(mySpa.scrrenRect.xMin, spa.scrrenRect.xMin); float xMax = Mathf.Min(mySpa.scrrenRect.xMax, spa.scrrenRect.xMax); float yMin = Mathf.Max(mySpa.scrrenRect.yMin, spa.scrrenRect.yMin); float yMax = Mathf.Min(mySpa.scrrenRect.yMax, spa.scrrenRect.yMax); if (cam.gameObject.name == "Main Camera" && gameObject.name == "Quad2") { Debug.Log("MySpa: " + mySpa); Debug.Log("plan: " + (xMin < xMax && yMin < yMax)); Debug.Log("Rec: xmin:" + xMin + " xmax:" + xMax + " ymin:" + yMin + " ymax:" + yMax); Debug.Log("Dep: " + (mySpa.maxDeep > spa.minDeep)); //Debug.Log(Vector3.Dot(portalPlaneRenderer.transform.position - cam.transform.position, portalForward) < 0); } return((motherPair != null && motherPair.portalA != null && motherPair.portalB != null && //GeometryUtility.TestPlanesAABB(planes, portalBounds) && xMin < xMax && yMin < yMax && mySpa.maxDeep > spa.minDeep && Vector3.Dot(portalPlaneRenderer.transform.position - cam.transform.position, portalForward) < 0) || (portalPlaneRenderer.transform.position - cam.transform.position).sqrMagnitude < SizeX * SizeY); }
private void BuildPortalViewTree(PortalNode p, int lastDepth) { if (lastDepth >= maxLayer) { return; } lastDepth++; Camera currentCam = p.thisPortal == null ? rootCamera : p.thisPortal.portalCamera; if (p.thisPortal != null) { currentCam.transform.position = p.position; currentCam.transform.rotation = p.rotation; currentCam.projectionMatrix = p.projMat; currentCam.targetTexture = p.rt; } ScreenPoatalArea portalRect = p.thisPortal == null ? new ScreenPoatalArea() { scrrenRect = new Rect(0, 0, 1, 1), minDeep = 0, maxDeep = currentCam.nearClipPlane } : p.thisPortal.otherPortal.GetPortalRect(currentCam); foreach (var pair in PortalPair.portalPairs) { if (pair.portalA != null && pair.portalA.ShouldCameraRender(currentCam, portalRect)) { p.nextPairs.Add(PortalNode.QueryNode(pair.portalA, lastDepth - 1)); } if (pair.portalB != null && pair.portalB.ShouldCameraRender(currentCam, portalRect)) { p.nextPairs.Add(PortalNode.QueryNode(pair.portalB, lastDepth - 1)); } } foreach (var node in p.nextPairs) { if (p.thisPortal != null) { currentCam.transform.position = p.position; currentCam.transform.rotation = p.rotation; currentCam.projectionMatrix = p.projMat; currentCam.targetTexture = p.rt; } Transform Source = node.thisPortal.portalPlaneTransform; Transform Destination = node.thisPortal.otherPortal.portalPlaneTransform; Camera portalCamera = node.thisPortal.portalCamera; // Rotate Source 180 degrees so PortalCamera is mirror image of MainCamera Matrix4x4 destinationFlipRotation = Matrix4x4.TRS(ZeroV3, Quaternion.AngleAxis(180.0f, Vector3.up), OneV3); Matrix4x4 sourceInvMat = destinationFlipRotation * Source.worldToLocalMatrix; // Calculate translation and rotation of MainCamera in Source space Vector3 cameraPositionInSourceSpace = ToV3(sourceInvMat * PosToV4(currentCam.transform.position)); Quaternion cameraRotationInSourceSpace = Quaternion.AngleAxis(180, Vector3.up) * Quaternion.Inverse(Source.rotation) * currentCam.transform.rotation; // Transform Portal Camera to World Space relative to Destination transform, // matching the Main Camera position/orientation portalCamera.transform.position = Destination.TransformPoint(cameraPositionInSourceSpace); portalCamera.transform.rotation = Destination.rotation * cameraRotationInSourceSpace; node.position = Destination.TransformPoint(cameraPositionInSourceSpace); node.rotation = Destination.rotation * cameraRotationInSourceSpace; // Calculate clip plane for portal (for culling of objects inbetween destination camera and portal) Vector4 clipPlaneWorldSpace = new Vector4(node.thisPortal.otherPortal.portalForward.x, node.thisPortal.otherPortal.portalForward.y, node.thisPortal.otherPortal.portalForward.z, Vector3.Dot(Destination.position, -node.thisPortal.otherPortal.portalForward)); Vector4 clipPlaneCameraSpace = Matrix4x4.Transpose(Matrix4x4.Inverse(portalCamera.worldToCameraMatrix)) * clipPlaneWorldSpace; // Update projection based on new clip plane // Note: http://aras-p.info/texts/obliqueortho.html and http://www.terathon.com/lengyel/Lengyel-Oblique.pdf //portalCamera.projectionMatrix = rootCamera.CalculateObliqueMatrix(clipPlaneCameraSpace); node.projMat = rootCamera.CalculateObliqueMatrix(clipPlaneCameraSpace); BuildPortalViewTree(node, lastDepth); } }