| @@ -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" | ||
| } |
| @@ -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 | ||
| } | ||
| } | ||
| } |