using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace UC { public class DoHomography : MonoBehaviour { [AutoUI(AutoUIAttribute.BindingFlag.NonSerialized)] public static bool show = false; [AutoUI(AutoUIAttribute.BindingFlag.NonSerialized)] public bool reset = false; [AutoUI] public Vector2 resolution; private Vector4 textureSize; public Texture cornerTexture; [AutoUI] public Vector2 destination1; [AutoUI] public Vector2 destination2; [AutoUI] public Vector2 destination3; [AutoUI] public Vector2 destination4; [AutoUI] public float cornerSize = 30; private Vector2[] source = new Vector2[4]; private Vector2[] destination = new Vector2[4]; //public Camera targetCamera; private List corners = null; public GameObject cornerCanvas; public Material mat; private static Matrix4x4 homo = new Matrix4x4(); public static Matrix4x4 gethomo { get { return homo; } } public RectTransform homoImagerect; public RenderTexture homoTexture; UIDragableObj GenerateCorner(string name) { //var obj = Instantiate(new GameObject(), transform); var obj = new GameObject(); obj.layer = LayerMask.NameToLayer("NoneSpout"); obj.transform.parent = transform; obj.transform.localPosition = Vector3.zero; obj.name = name; var raw_image = obj.AddComponent(); raw_image.color = new Color(189.0f / 255.0f, 73.0f / 255.0f, 50.0f / 255.0f,0); raw_image.texture = cornerTexture; var rt = obj.GetComponent(); rt.sizeDelta = new Vector2(cornerSize, cornerSize); var corner = obj.AddComponent(); return corner; } void ResetCorners() { if (corners == null) { corners = new List(); corners.Add(GenerateCorner("TopLeft")); corners.Add(GenerateCorner("TopRight")); corners.Add(GenerateCorner("BottomRight")); corners.Add(GenerateCorner("BottomLeft")); } destination[0] = corners[0].position = new Vector2(-resolution.x, resolution.y)/2; destination[1] = corners[1].position = new Vector2(resolution.x, resolution.y)/2; destination[2] = corners[2].position = new Vector2(resolution.x, -resolution.y)/2; destination[3] = corners[3].position = new Vector2(-resolution.x, -resolution.y)/2; source[0] = new Vector2((-resolution.x )/ (float)Screen.width , (resolution.y ) / (float)Screen.height ); source[1] = new Vector2((resolution.x ) / (float)Screen.width , (resolution.y) / (float)Screen.height ); source[2] = new Vector2((resolution.x ) / (float)Screen.width , (-resolution.y ) / (float)Screen.height ); source[3] = new Vector2((-resolution.x ) / (float)Screen.width , (-resolution.y ) / (float)Screen.height ); foreach (Vector2 vec in source) print(vec); } void Start() { ResetCorners(); //homoImagerect.sizeDelta = resolution; homoImagerect.GetComponent().texture = homoTexture; Vector2 des_scale = new Vector2( (float)Screen.width / 2.0f, (float)Screen.height / 2.0f); corners[0].position = Vector2.Scale(destination1, des_scale); corners[1].position = Vector2.Scale(destination2, des_scale); corners[2].position = Vector2.Scale(destination3, des_scale); corners[3].position = Vector2.Scale(destination4, des_scale); DoHomo(); ViewCorner(); lines = new GUILine[4]; for (int i = 0; i < lines.Length; i++) { lines[i] = new GUILine(); } SetLinePos(); /* destination[0] = new Vector2(0, 0); // TL destination[1] = new Vector2(1, 0); // TR destination[2] = new Vector2(0, 1); // BL destination[3] = new Vector2(1, 1); // BR */ //textureSize = new Vector4(resolution.x, resolution.y, 0, 0); } void SetLinePos() { for (int i = 0; i < lines.Length; i++) { if(i+1 < lines.Length) { lines[i].startPt = corners[i].position + (new Vector2((float)Screen.width, (float)Screen.height) /2) ; lines[i].endPt = corners[i+1].position + (new Vector2((float)Screen.width, (float)Screen.height) / 2); // print(destination[i] + ";"+ destination[i+1]); } else { lines[i].startPt = corners[i].position + (new Vector2((float)Screen.width, (float)Screen.height) / 2); lines[i].endPt = corners[0].position + (new Vector2((float)Screen.width, (float)Screen.height) / 2); } lines[i].startPt.y = Screen.height -lines[i].startPt.y; lines[i].endPt.y = Screen.height - lines[i].endPt.y; } } void Update() { #if false if (reset) { reset = false; ResetCorners(); } if (Input.GetKeyDown(KeyCode.F2)) { show = !show; } var cg = GetComponent(); cg.alpha = show ? 1.0f : 0.0f; cg.interactable = cg.blocksRaycasts = show; for (int i = 0; i < source.Length; i++) { source[i] = corners[i].position; } Vector2 mul = new Vector2(1.0f / resolution.x, 1.0f / resolution.y); for (int i = 0; i <= 3; i++) { source[i].y = resolution.y - source[i].y; source[i] = Vector2.Scale(source[i], mul); } var homography = targetCamera.GetComponent(); if (homography == null) homography = targetCamera.gameObject.AddComponent(); homography.material.SetMatrix("matrixHomo", homo); homography.material.SetVector("textureSize", textureSize); #endif ViewCorner(); if (Input.GetKeyDown(KeyCode.C)) { show = !show; ViewCorner(); } if (!show) return; DoHomo(); } void ViewCorner() { foreach (UIDragableObj homocorner in corners) { homocorner.gameObject.SetActive(show); } } void DoHomo() { Vector2 des_scale = new Vector2(2.0f / (float)Screen.width, 2.0f / (float)Screen.height); for (int i = 0; i < destination.Length; i++) { destination[i] = corners[i].position; destination[i].y = -destination[i].y; SetLinePos(); destination[i] = Vector2.Scale(destination[i], des_scale); } destination1 = destination[0]; destination2 = destination[1]; destination3 = destination[2]; destination4 = destination[3]; destination1.y = -destination1.y; destination2.y = -destination2.y; destination3.y = -destination3.y; destination4.y = -destination4.y; FindHomography(ref source, ref destination, ref homo); mat.SetMatrix("matrixH", homo); } public struct GUILine { public Vector2 startPt; public Vector2 endPt; } private GUILine[] lines = new GUILine[4]; private float length = 10; private void OnGUI() { if(show) { foreach (GUILine line in lines) { Texture2D lineTex = new Texture2D(10, 10); Matrix4x4 matrixBackup = GUI.matrix; float width = 8.0f; GUI.color = Color.red; length = (line.startPt - line.endPt).magnitude; float angle = Mathf.Atan2(line.endPt.y - line.startPt.y, line.endPt.x - line.startPt.x) * 180f / Mathf.PI; GUIUtility.RotateAroundPivot(angle, line.startPt); GUI.DrawTexture(new Rect(line.startPt.x,line.startPt.y, length, width), lineTex); GUI.matrix = matrixBackup; float t_size = 60; GUI.DrawTexture(new Rect(line.startPt.x - t_size/2, line.startPt.y - t_size/2, t_size, t_size), lineTex); } } } void setLinePoints(GUILine line) { line.startPt = setPoint(line.startPt); line.endPt = setPoint(line.endPt); length = (line.startPt - line.endPt).magnitude; } Vector2 setPoint(Vector2 point) { point.x = (int)point.x; point.y = Screen.height - (int)point.y; return point; } void DrawLine(Vector2 pointA, Vector2 pointB) { pointA = setPoint(pointA); pointB = setPoint(pointB); Texture2D lineTex = new Texture2D(1, 1); Matrix4x4 matrixBackup = GUI.matrix; float width = 8.0f; GUI.color = Color.red; float angle = Mathf.Atan2(pointB.y - pointA.y, pointB.x - pointA.x) * 180f / Mathf.PI; GUIUtility.RotateAroundPivot(angle, pointA); GUI.DrawTexture(new Rect(pointA.x, pointA.y, length, width), lineTex); GUI.matrix = matrixBackup; } void FindHomography(ref Vector2[] src, ref Vector2[] dest, ref Matrix4x4 homography) { float[,] P = new float[,]{ {-src[0].x, -src[0].y, -1, 0, 0, 0, src[0].x*dest[0].x, src[0].y*dest[0].x, -dest[0].x }, // h11 { 0, 0, 0, -src[0].x, -src[0].y, -1, src[0].x*dest[0].y, src[0].y*dest[0].y, -dest[0].y }, // h12 {-src[1].x, -src[1].y, -1, 0, 0, 0, src[1].x*dest[1].x, src[1].y*dest[1].x, -dest[1].x }, // h13 { 0, 0, 0, -src[1].x, -src[1].y, -1, src[1].x*dest[1].y, src[1].y*dest[1].y, -dest[1].y }, // h21 {-src[2].x, -src[2].y, -1, 0, 0, 0, src[2].x*dest[2].x, src[2].y*dest[2].x, -dest[2].x }, // h22 { 0, 0, 0, -src[2].x, -src[2].y, -1, src[2].x*dest[2].y, src[2].y*dest[2].y, -dest[2].y }, // h23 {-src[3].x, -src[3].y, -1, 0, 0, 0, src[3].x*dest[3].x, src[3].y*dest[3].x, -dest[3].x }, // h31 { 0, 0, 0, -src[3].x, -src[3].y, -1, src[3].x*dest[3].y, src[3].y*dest[3].y, -dest[3].y }, // h32 }; GaussianElimination(ref P, 9); float[] aux_H ={ P[0,8],P[3,8],0,P[6,8], // h11 h21 0 h31 P[1,8],P[4,8],0,P[7,8], // h12 h22 0 h32 0 , 0,1,0, // 0 0 0 0 P[2,8],P[5,8],0,1}; // h13 h23 0 h33 for (int i = 0; i < 16; i++) homography[i] = aux_H[i]; } void GaussianElimination(ref float[,] A, int n) { int i = 0; int j = 0; int m = n - 1; while (i < m && j < n) { int maxi = i; for (int k = i + 1; k < m; k++) { if (Mathf.Abs(A[k, j]) > Mathf.Abs(A[maxi, j])) { maxi = k; } } if (A[maxi, j] != 0) { if (i != maxi) for (int k = 0; k < n; k++) { float aux = A[i, k]; A[i, k] = A[maxi, k]; A[maxi, k] = aux; } float A_ij = A[i, j]; for (int k = 0; k < n; k++) { A[i, k] /= A_ij; } for (int u = i + 1; u < m; u++) { float A_uj = A[u, j]; for (int k = 0; k < n; k++) { A[u, k] -= A_uj * A[i, k]; } } i++; } j++; } for (int k = m - 2; k >= 0; k--) { for (int l = k + 1; l < n - 1; l++) { A[k, m] -= A[k, l] * A[l, m]; } } } } /* public static Vector2 UIPosToHomographyPos(Vector2 vec) { vec.y = -vec.y; vec = new Vector2(vec.x * 2 / (float)Screen.width, vec.y * 2 / (float)Screen.height); Vector2 nnn_pos = new Vector2(Input.mousePosition.x, Input.mousePosition.y) - new Vector2(Screen.width, Screen.height) / 2; Vector2 aa22 = new Vector2(Input.mousePosition.x, Input.mousePosition.y) - new Vector2(Screen.width, Screen.height) / 2; Vector2 aa = nnn_pos; nnn_pos.y = -nnn_pos.y; nnn_pos = new Vector2(nnn_pos.x * 2 / (float)Screen.width, nnn_pos.y * 2 / (float)Screen.height); nnn_pos = UC.DoHomography.gethomo.inverse.MultiplyPoint(nnn_pos); nnn_pos.y = -nnn_pos.y; nnn_pos = new Vector2(nnn_pos.x * (float)Screen.width / 2, nnn_pos.y * (float)Screen.height / 2); nnn_pos = nnn_pos + new Vector2(Screen.width, Screen.height) / 2; nnn_pos.y = Screen.height - nnn_pos.y; nnn_pos = nnn_pos - new Vector2(Screen.width, Screen.height) / 2; } */ }