📜 ⬆️ ⬇️

Create anamorphic distortion in Unity

Hello! Now I work in VRTech, and as part of the work I came across an interesting task about which I want to tell. The task was to get an anamorphic image display. I will try to tell you what anamorphic distortion is, how to calculate the simplest case of a linear mapping of such distortion to a plane, and also suggest my solution implemented using Unity.

image

Recently, at work I was offered an interesting puzzle, to find on the leaf how to convert the image to create anamorphic distortion. I like mathematics, for this reason I became interested, because I had never heard of them. What is anamorphic distortion?

In general, optical anamorphization is a method of image distortion, which involves a different scale of transformation in two mutually perpendicular directions. In general, it is used to remove perspective distortions, but it has also become quite a popular tool in art.
')


To create a plausible effect, a viewpoint is a very important detail. If you have seen 3D art on the street, then you understand that the step is right, the step is left and the illusion disintegrates.

After reading the articles on how such a transformation is done and realizing that in general there is nothing difficult in this, I, as a programmer, thought that probably somewhere on the Internet there is already a ready-made library. And ideally, such a library should provide functionality to parametrically set the viewpoint, the estimated height of the image and other buns. I found a couple of solutions, but none of them worked. So I had to write my own.

Let's go over the way such an image is built. Initially, the desired result is taken and broken into a grid. The finer the mesh, the more accurate the solution. In Unity, I decided to simply generate a mesh that can control the number of cells in the grid.



Next, select the viewpoint and the plane on which we will build our mapping. After that, in a flat case in a trivial way, we simply draw straight lines that pass the grid points and the viewpoint.



The choice of the tool fell on Unity, since I know it very well, as well as all the articles that I found on the Internet were written in a popular, rather than mathematical language, and I wanted to check the correctness of the algorithm operation without unnecessary gestures (without printing the solution , and thinking what is wrong here). In Unity, this is very simple to implement, since the result can be viewed through the camera in 3D space. In addition, there is a implemented toolkit for working with 3D, vectors, etc.

According to the list of features, the decision should have received an image at the entrance, the user's point of view, the height (in meters) of the result from the user's point of view, as well as the accuracy of the decision.

In order to make it all as easy as possible, I decided to make the easiest solution. Generate the mesh by correctly placing uv coordinates on it, drag the desired image onto it. Next, using the projection, generate a new mesh with new vertices and normals, but with the old uv coordinates.

The first task is solved quite simply, since the mesh has a simple structure, and it was necessary to generate a simple grid and number the triangles correctly. The mesh in this case is the plane on which the picture is stretched entirely, so that the correct placement of the uv coordinates is also not difficult.
Kitty for tests you have already seen, but I will show it without “light,” so it is more beautiful.



Mesh generated, then it was necessary to calculate new vertices and new normals. I decided to define new vertices by defining the point of intersection of a line drawn through two points and a plane defined by three points. The method of determining the intersection point between a plane and a straight line requires the determination of the normal to the plane, so that the new normals were also calculated.

Spoiler header
private Vector3 GetIntersectionOfLineAndPlane( Vector3 linePoint1, Vector3 linePoint2, Vector3 planePoint1, Vector3 planePoint2, Vector3 planePoint3, ref Vector3 planeNormal) { Vector3 result = new Vector3(); planeNormal = Vector3.Cross(planePoint2 - planePoint1, planePoint3 - planePoint1); planeNormal.Normalize(); Debug.Log(planeNormal.ToString()); var distance = Vector3.Dot(planeNormal, planePoint1 - linePoint1); var w = linePoint2 - linePoint1; var e = Vector3.Dot(planeNormal, w); if(e != 0) { result = new Vector3( linePoint1.x + wx * distance / e, linePoint1.y + wy * distance / e, linePoint1.z + wz * distance / e); } else { result = Vector3.one * (-505); } return result; } } 


Everything, the decision is ready! In general, the task is quite simple, but at the same time interesting. I think on this effect, you can even make a pretty funny game and break the brains of the players. In the video you can see the result of the work. (The original picture on the video is very dark, since I did not adjust the light)



A little later, I can finish the functional so that I can project on several planes, as well as on reflective surfaces and achieve an effect like this.



Directly with the decision code, as well as to monitor its possible further development can be here .

Source: https://habr.com/ru/post/320926/


All Articles