@@ -0,0 +1,200 @@
// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/EdgeBlend2"
{
Properties
{
_NumCams("NumCams",Range(1,6)) = 2
_TargetCam("TargetCam",Range(0,6)) = 0
_Fade("Fade",Range(-10,1)) = 0
_Expo("Expo",Range(0,10)) = 0.1

_MainTex("Main Tex",2D) = "white"{}


}

SubShader
{
Tags{ "RenderType" = "Opaque" "Queue" = "Overlay" }
LOD 100

ZTest Always //Draw no matter what
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha //Alpha Blending

Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#include "UnityCG.cginc"

float4x4 _Cam1Matrix;
float4x4 _Cam2Matrix;
float4x4 _Cam3Matrix;
float4x4 _Cam4Matrix;
float4x4 _Cam5Matrix;
float4x4 _Cam6Matrix;

float _Fade;
float _Expo;
float _NumCams;
float _TargetCam;

uniform sampler2D _MainTex;
float4 _MainTex_ST;

uniform sampler2D _DistTex;
float4 _DistTex_ST;


struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;

};

struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : POSITION;
float2 camUV1 : TEXCOORD1;
float2 camUV2 : TEXCOORD2;
float2 camUV3 : TEXCOORD3;
float2 camUV4 : TEXCOORD4;
float2 camUV5 : TEXCOORD5;
float2 camUV6 : TEXCOORD6;
};


v2f vert(appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;

float4 camVertex1 = mul(_Cam1Matrix, v.vertex);
o.camUV1 = (camVertex1 / camVertex1.w)*.5 + .5;

float4 camVertex2 = mul(_Cam2Matrix, v.vertex);
o.camUV2 = (camVertex2 / camVertex2.w)*.5 + .5;

float4 camVertex3 = mul(_Cam3Matrix, v.vertex);
o.camUV3 = (camVertex3 / camVertex3.w)*.5 + .5;

float4 camVertex4 = mul(_Cam4Matrix, v.vertex);
o.camUV4 = (camVertex4 / camVertex4.w)*.5 + .5;

float4 camVertex5 = mul(_Cam5Matrix, v.vertex);
o.camUV5 = (camVertex5 / camVertex5.w)*.5 + .5;

float4 camVertex6 = mul(_Cam6Matrix, v.vertex);
o.camUV6 = (camVertex6 / camVertex6.w)*.5 + .5;


return o;
}


fixed4 frag(v2f i) : SV_Target
{

float2 camUV[6] = {i.camUV1,i.camUV2,i.camUV3,i.camUV4,i.camUV5,i.camUV6};
bool isInside[6];
fixed numInsides = 0;

for (int c = 0; c < _NumCams; c++)
{
isInside[c] = camUV[c].x >= 0 && camUV[c].y >= 0 && camUV[c].x <= 1 && camUV[c].y <= 1;
//borders[c] = (camUV[c].x - _Dist < 0 || camUV[c].y - _Dist < 0 || camUV[c].x + _Dist > 1 || camUV[c].y + _Dist > 1);
if (isInside[c])
{
numInsides++;
}
}

//bool isOutsideCam1 = (i.camUV1.x < 0 || i.camUV1.y < 0 || i.camUV1.x > 1 || i.camUV1.y > 1);
//bool isOutsideCam2 = (i.camUV2.x < 0 || i.camUV2.y < 0 || i.camUV2.x > 1 || i.camUV2.y > 1);

//bool isCam1Border = (i.camUV1.x - _Dist < 0 || i.camUV1.y - _Dist < 0 || i.camUV1.x + _Dist > 1 || i.camUV1.y + _Dist > 1);
//bool isCam2Border = (i.camUV2.x - _Dist < 0 || i.camUV2.y - _Dist < 0 || i.camUV2.x + _Dist > 1 || i.camUV2.y + _Dist > 1);


if (numInsides == 0)
{
return fixed4(0, 0, 0, .3f);
/*} else if (isOutsideCam1)
{
return fixed4(0, 1, 0, 1);
} else if (isOutsideCam2)
{
return fixed4(1, 0, 0, 1);
*/
}else
{

if (_TargetCam > 0 && !isInside[_TargetCam - 1]) return fixed4(0, 0, 0, .5);

float camDists[6];
fixed4 cols[6];
float totalDist = 0;

for (float c = 0; c < _NumCams; c++)
{
cols[c] = fixed4(fmod((c + 1)*1.2, 1), fmod((c + 1)*1.5, 1), fmod((c + 1)*1.7, 1), 1);
if (isInside[c])
{
float2 d = 1 - abs(camUV[c].xy - .5)*abs(camUV[c].xy - .5) * 4;
camDists[c] = d.x*d.y;
totalDist += camDists[c];
} else
{
camDists[c] = 0;
}
}

fixed4 col = fixed4(0, 0, 0, 1);
float weights[6];
float totalWeight = 0;

for (int c2 = 0; c2 < _NumCams; c2++)
{
float p = camDists[c2] / totalDist;

//Fading for smoother/harder transition
const float PI = 3.14159;
p = p * 2 * PI;
p += _Fade*sin(p);
p = p / (2 * PI);
p = min(max(p, 0), 1);

//adjust exposition
p += _Expo*(.25 - (p - .5)*(p - .5));
totalWeight += p;
weights[c2] = p;
}
for (c2 = 0; c2 < _NumCams; c2++)
{
float p = weights[c2] / totalWeight;
if (totalWeight == 0) p = 1 + _Expo*.25 / _NumCams;
if (isInside[c2])
{
col += cols[c2] * p;
}

if(floor(_TargetCam) == c2+1) return fixed4(p, p, p, 1);
}

col.a = 1;
return col;
}
}
ENDCG
}
}

FallBack "Diffuse"
}
BIN +1.98 KB (110%) Assets/Main.unity
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,197 @@
// This script should be attached to a Camera object
// in Unity. Once a Plane object is specified as the
// "projectionScreen", the script computes a suitable
// view and projection matrix for the camera.
// The code is based on Robert Kooima's publication
// "Generalized Perspective Projection," 2009,
// http://csc.lsu.edu/~kooima/pdfs/gen-perspective.pdf

// Use the following line to apply the script in the editor:
@script ExecuteInEditMode()

#pragma strict


public var projectionScreen : GameObject;
public var screenWidth : float;
public var screenHeight : float;

public var estimateViewFrustum : boolean = true;
public var setNearClipPlane : boolean = false;
public var nearClipDistanceOffset : float = -0.01;

private var cameraComponent : Camera;

function LateUpdate() {
cameraComponent = GetComponent(Camera);
if (null != projectionScreen && null != cameraComponent)
{
var pa : Vector3 =
projectionScreen.transform.TransformPoint(
Vector3(-screenWidth/2, -screenHeight/2, 0.0));
// lower left corner in world coordinates
var pb : Vector3 =
projectionScreen.transform.TransformPoint(
Vector3(screenWidth/2, -screenHeight/2, 0.0));
// lower right corner
var pc : Vector3 =
projectionScreen.transform.TransformPoint(
Vector3(-screenWidth/2, screenHeight/2,0));
// upper left corner
var pe : Vector3 = transform.position;
// eye position
var n : float = cameraComponent.nearClipPlane;
// distance of near clipping plane
var f : float = cameraComponent.farClipPlane;
// distance of far clipping plane

var va : Vector3; // from pe to pa
var vb : Vector3; // from pe to pb
var vc : Vector3; // from pe to pc
var vr : Vector3; // right axis of screen
var vu : Vector3; // up axis of screen
var vn : Vector3; // normal vector of screen

var l : float; // distance to left screen edge
var r : float; // distance to right screen edge
var b : float; // distance to bottom screen edge
var t : float; // distance to top screen edge
var d : float; // 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);
if (setNearClipPlane)
{
n = d + nearClipDistanceOffset;
cameraComponent.nearClipPlane = n;
}
l = Vector3.Dot(vr, va) * n / d;
r = Vector3.Dot(vr, vb) * n / d;
b = Vector3.Dot(vu, va) * n / d;
t = Vector3.Dot(vu, vc) * n / d;

var p : Matrix4x4; // projection matrix
p[0,0] = 2.0*n/(r-l);
p[0,1] = 0.0;
p[0,2] = (r+l)/(r-l);
p[0,3] = 0.0;

p[1,0] = 0.0;
p[1,1] = 2.0*n/(t-b);
p[1,2] = (t+b)/(t-b);
p[1,3] = 0.0;

p[2,0] = 0.0;
p[2,1] = 0.0;
p[2,2] = (f+n)/(n-f);
p[2,3] = 2.0*f*n/(n-f);

p[3,0] = 0.0;
p[3,1] = 0.0;
p[3,2] = -1.0;
p[3,3] = 0.0;

var rm : Matrix4x4; // rotation matrix;
rm[0,0] = vr.x;
rm[0,1] = vr.y;
rm[0,2] = vr.z;
rm[0,3] = 0.0;

rm[1,0] = vu.x;
rm[1,1] = vu.y;
rm[1,2] = vu.z;
rm[1,3] = 0.0;

rm[2,0] = vn.x;
rm[2,1] = vn.y;
rm[2,2] = vn.z;
rm[2,3] = 0.0;

rm[3,0] = 0.0;
rm[3,1] = 0.0;
rm[3,2] = 0.0;
rm[3,3] = 1.0;

var tm : Matrix4x4; // translation matrix;
tm[0,0] = 1.0;
tm[0,1] = 0.0;
tm[0,2] = 0.0;
tm[0,3] = -pe.x;

tm[1,0] = 0.0;
tm[1,1] = 1.0;
tm[1,2] = 0.0;
tm[1,3] = -pe.y;

tm[2,0] = 0.0;
tm[2,1] = 0.0;
tm[2,2] = 1.0;
tm[2,3] = -pe.z;

tm[3,0] = 0.0;
tm[3,1] = 0.0;
tm[3,2] = 0.0;
tm[3,3] = 1.0;

// set matrices
cameraComponent.projectionMatrix = p;
cameraComponent.worldToCameraMatrix = rm * tm;
// The original paper puts everything into the projection
// matrix (i.e. sets it to p * rm * tm and the other
// matrix to the identity), but this doesn't appear to
// work with Unity's shadow maps.

if (estimateViewFrustum)
{
// rotate camera to screen for culling to work
var q : Quaternion;
q.SetLookRotation((0.5 * (pb + pc) - pe), vu);
// look at center of screen
cameraComponent.transform.rotation = q;

// set fieldOfView to a conservative estimate
// to make frustum tall enough
if (cameraComponent.aspect >= 1.0)
{
cameraComponent.fieldOfView = Mathf.Rad2Deg *
Mathf.Atan(((pb-pa).magnitude + (pc-pa).magnitude)
/ va.magnitude);
}
else
{
// take the camera aspect into account to
// make the frustum wide enough
cameraComponent.fieldOfView =
Mathf.Rad2Deg / cameraComponent.aspect *
Mathf.Atan(((pb-pa).magnitude + (pc-pa).magnitude)
/ va.magnitude);
}
}
}
}
@@ -0,0 +1,97 @@
using UnityEngine;

[ExecuteInEditMode]
public class OffCenterPerspective : MonoBehaviour {

public Transform[] Corners;
public Transform lookTarget;
public bool drawNearCone, drawFrustum;

Camera theCam;

void Start()
{
theCam = GetComponent<Camera>();
}

void Update()
{
if (theCam == null) theCam = GetComponent<Camera>();

Vector3 pa, pb, pc, pd;
pa = Corners[0].position;
pb = Corners[1].position;
pc = Corners[2].position;
pd = Corners[3].position;

Vector3 pe = theCam.transform.position;// eye position

Vector3 vr = (pb - pa).normalized; // right axis of screen
Vector3 vu = (pc - pa).normalized; // up axis of screen
Vector3 vn = Vector3.Cross(vr, vu).normalized; // normal vector of screen

Vector3 va = pa - pe; // from pe to pa
Vector3 vb = pb - pe; // from pe to pb
Vector3 vc = pc - pe; // from pe to pc
Vector3 vd = pd - pe; // from pe to pd

float n = -lookTarget.InverseTransformPoint(theCam.transform.position).z; // distance to the near clip plane (screen)
float f = theCam.farClipPlane; // distance of far clipping plane
float d = Vector3.Dot(va, vn); // distance from eye to screen
float l = Vector3.Dot(vr, va) * n / d; // distance to left screen edge from the 'center'
float r = Vector3.Dot(vr, vb) * n / d; // distance to right screen edge from 'center'
float b = Vector3.Dot(vu, va) * n / d; // distance to bottom screen edge from 'center'
float t = Vector3.Dot(vu, vc) * n / d; // distance to top screen edge from 'center'

Matrix4x4 p = new Matrix4x4(); // Projection matrix
p[0, 0] = 2.0f * n / (r - l);
p[0, 2] = (r + l) / (r - l);
p[1, 1] = 2.0f * n / (t - b);
p[1, 2] = (t + b) / (t - b);
p[2, 2] = (f + n) / (n - f);
p[2, 3] = 2.0f * f * n / (n - f);
p[3, 2] = -1.0f;

theCam.projectionMatrix = p; // Assign matrix to camera

if (drawNearCone)
{ //Draw lines from the camera to the corners f the screen
Debug.DrawRay(theCam.transform.position, va, Color.blue);
Debug.DrawRay(theCam.transform.position, vb, Color.blue);
Debug.DrawRay(theCam.transform.position, vc, Color.blue);
Debug.DrawRay(theCam.transform.position, vd, Color.blue);
}

if (drawFrustum) DrawFrustum(theCam); //Draw actual camera frustum

}

Vector3 ThreePlaneIntersection(Plane p1, Plane p2, Plane p3)
{ //get the intersection point of 3 planes
return ((-p1.distance * Vector3.Cross(p2.normal, p3.normal)) +
(-p2.distance * Vector3.Cross(p3.normal, p1.normal)) +
(-p3.distance * Vector3.Cross(p1.normal, p2.normal))) /
(Vector3.Dot(p1.normal, Vector3.Cross(p2.normal, p3.normal)));
}

void DrawFrustum(Camera cam)
{
Vector3[] nearCorners = new Vector3[4]; //Approx'd nearplane corners
Vector3[] farCorners = new Vector3[4]; //Approx'd farplane corners
Plane[] camPlanes = GeometryUtility.CalculateFrustumPlanes(cam); //get planes from matrix
Plane temp = camPlanes[1]; camPlanes[1] = camPlanes[2]; camPlanes[2] = temp; //swap [1] and [2] so the order is better for the loop

for (int i = 0; i < 4; i++)
{
nearCorners[i] = ThreePlaneIntersection(camPlanes[4], camPlanes[i], camPlanes[(i + 1) % 4]); //near corners on the created projection matrix
farCorners[i] = ThreePlaneIntersection(camPlanes[5], camPlanes[i], camPlanes[(i + 1) % 4]); //far corners on the created projection matrix
}

for (int i = 0; i < 4; i++)
{
Debug.DrawLine(nearCorners[i], nearCorners[(i + 1) % 4], Color.red, Time.deltaTime, false); //near corners on the created projection matrix
Debug.DrawLine(farCorners[i], farCorners[(i + 1) % 4], Color.red, Time.deltaTime, false); //far corners on the created projection matrix
Debug.DrawLine(nearCorners[i], farCorners[i], Color.red, Time.deltaTime, false); //sides of the created projection matrix
}
}
}
BIN +204 Bytes (100%) Assets/PlaneMat.mat
Binary file not shown.
BIN +21.3 KB Assets/Test.unity
Binary file not shown.
BIN +44.5 KB Assets/greyMask.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +255 KB Assets/stage.fbx
Binary file not shown.