Created
July 10, 2022 15:42
-
-
Save D4KU/c49a02fb15d3c452fa10aa05fe96eb0e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using UnityEngine; | |
| using MathNet.Numerics.LinearAlgebra; | |
| /// <summary> | |
| /// Apply transformation matrix reconstructed from four points to a material. | |
| /// The matrix describes the transformation of the screen rectangle to the | |
| /// quadrilateral spanned by the points after being projected in the screen | |
| /// space of the connected camera. | |
| /// </summary> | |
| /// <author>David Kutschke</author> | |
| [ExecuteAlways] | |
| [RequireComponent(typeof(Camera))] | |
| public class MatrixFromPoints : MonoBehaviour | |
| { | |
| // Four points to calculate transformation matrix from | |
| public Transform bottomLeft; | |
| public Transform bottomRight; | |
| public Transform topLeft; | |
| public Transform topRight; | |
| [Tooltip("Material to apply the calculated matrix to")] | |
| public Material material; | |
| [Tooltip("Shader property to apply the calculated matrix to")] | |
| public string propertyName = "_Matrix"; | |
| new Camera camera; | |
| public Camera Camera | |
| { | |
| get | |
| { | |
| if (camera == null) | |
| camera = GetComponent<Camera>(); | |
| return camera; | |
| } | |
| } | |
| void Update() | |
| { | |
| if (!(bottomLeft && bottomRight && topLeft && topRight && material)) | |
| return; | |
| var cam = Camera; | |
| Matrix4x4 matrix = GetPerspective( | |
| Vector2.zero, | |
| Vector2.right, | |
| Vector2.up, | |
| Vector2.one, | |
| cam.WorldToViewportPoint(bottomLeft.position), | |
| cam.WorldToViewportPoint(bottomRight.position), | |
| cam.WorldToViewportPoint(topLeft.position), | |
| cam.WorldToViewportPoint(topRight.position)); | |
| material.SetMatrix(propertyName, matrix); | |
| } | |
| /// <summary> | |
| /// Reconstruct transformation matrix from the transformation of four | |
| /// source points to four target points. | |
| /// c --- d g -- h | |
| /// | | | | | |
| /// | | -> | | | |
| /// a --- b e -- f | |
| /// </summary> | |
| /// <returns> | |
| /// 3x3 Matrix, padded as 4x4 because it's the only one Unity supports. | |
| /// </returns> | |
| static Matrix4x4 GetPerspective( | |
| Vector2 a, Vector2 b, Vector2 c, Vector2 d, | |
| Vector2 e, Vector2 f, Vector2 g, Vector2 h) | |
| { | |
| // Taken from | |
| // https://stackoverflow.com/a/57280136/5634963 | |
| // Solve system of linear equations Ax = b | |
| // Build coefficient matrix A | |
| var A = Matrix<float>.Build.DenseOfArray(new float[,] | |
| { | |
| { a.x, a.y, 1, 0, 0, 0, -a.x * e.x, -a.y * e.x }, | |
| { b.x, b.y, 1, 0, 0, 0, -b.x * f.x, -b.y * f.x }, | |
| { c.x, c.y, 1, 0, 0, 0, -c.x * g.x, -c.y * g.x }, | |
| { d.x, d.y, 1, 0, 0, 0, -d.x * h.x, -d.y * h.x }, | |
| { 0, 0, 0, a.x, a.y, 1, -a.x * e.y, -a.y * e.y }, | |
| { 0, 0, 0, b.x, b.y, 1, -b.x * f.y, -b.y * f.y }, | |
| { 0, 0, 0, c.x, c.y, 1, -c.x * g.y, -c.y * g.y }, | |
| { 0, 0, 0, d.x, d.y, 1, -d.x * h.y, -d.y * h.y }, | |
| }); | |
| // Build vector b in Ax = b | |
| var _b = Vector<float>.Build.DenseOfArray(new float[] | |
| { | |
| e.x, f.x, g.x, h.x, e.y, f.y, g.y, h.y | |
| }); | |
| // Find solution vector x in Ax = b | |
| // x = A \ b | |
| // x = A^-1 * b | |
| var x = A.Inverse() * _b; | |
| return new Matrix4x4( | |
| column0: new Vector4(x[0], x[3], x[6], 0), | |
| column1: new Vector4(x[1], x[4], x[7], 0), | |
| column2: new Vector4(x[2], x[5], 1, 0), | |
| column3: new Vector4( 0, 0, 0, 1)); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Shader "Unlit/SampleTransformed" | |
| { | |
| Properties | |
| { | |
| _MainTex ("Texture", 2D) = "white" {} | |
| } | |
| SubShader | |
| { | |
| Tags { "RenderType"="Opaque" } | |
| LOD 100 | |
| Pass | |
| { | |
| CGPROGRAM | |
| #pragma vertex vert | |
| #pragma fragment frag | |
| // make fog work | |
| #pragma multi_compile_fog | |
| #include "UnityCG.cginc" | |
| struct appdata | |
| { | |
| float4 vertex : POSITION; | |
| float2 uv : TEXCOORD0; | |
| }; | |
| struct v2f | |
| { | |
| float2 uv : TEXCOORD0; | |
| UNITY_FOG_COORDS(1) | |
| float4 vertex : SV_POSITION; | |
| }; | |
| CBUFFER_START(UnityPerMaterial) | |
| sampler2D _MainTex; | |
| float4 _MainTex_ST; | |
| float4x4 _Matrix; | |
| CBUFFER_END | |
| v2f vert (appdata v) | |
| { | |
| v2f o; | |
| o.vertex = UnityObjectToClipPos(v.vertex); | |
| o.uv = TRANSFORM_TEX(v.uv, _MainTex); | |
| UNITY_TRANSFER_FOG(o,o.vertex); | |
| return o; | |
| } | |
| fixed4 frag (v2f i) : SV_Target | |
| { | |
| float3 uv = mul(_Matrix, float3(i.uv, 1)); | |
| return tex2D(_MainTex, uv.xy / uv.z); | |
| } | |
| ENDCG | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment