You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

401 lines
14 KiB

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<UIDragableObj> 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<RawImage>();
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<RectTransform>();
rt.sizeDelta = new Vector2(cornerSize, cornerSize);
var corner = obj.AddComponent<UIDragableObj>();
return corner;
}
void ResetCorners()
{
if (corners == null)
{
corners = new List<UIDragableObj>();
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<RawImage>().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<CanvasGroup>();
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<ScreenHomography>();
if (homography == null)
homography = targetCamera.gameObject.AddComponent<ScreenHomography>();
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;
}
*/
}