Measure Distances App
In order to be able to measure distances using the phone camera, we can use ARCore. We have seen yesterday we can place objects on screen just by clicking on screen. What if we can measure real life distances just by clicking on screen? For instance, in we click two times on the screen we will get the distance between the two points. If we click another time, we will get both the total distance between the three points and the distacne between the last two added points.
So, in order to do this, you will need to download the sources for this project. The project it's quite complex, so you will have the basic part of the project already implemented. You will only add the missing pieces of code.
First of all, you need to download the sources and to extract its content. Then, open Unity Hub and click on the ADD button. Go to the folder with the project and select it. Wait for the project to load. 😅
Once you open the project, click in Hierarchy on HelloAR Component object. In Inspector, you will see it has a script attached to it: HelloARController. Open it. Here is where all the magic is happening. This script at the moment does the exact same thing as the script from the HelloAR example. When we click on sceen, an object is displayed. This time, however, on screen will appear points, not androids. What should we do next?
- Draw a line between the last two added points.
- Compute the distance between the last two added points and display it on screen.
- Compute the total distance and display it on screen.
Let's see how we can do all these. Everywhere where we need to change the code we have a TODO comment placed which explains us what we need to do.
Draw Lines between Points
In order to implement this, we need to look at lines 192-204. Here we have 4 TODOs. So, there are 4 things which we need to immplement. But before we start implementing, we need to understand what we are going to do. So we need to draw a line between 2 points.
1. In the HelloAR example you have seen we can draw objects on screen using prefabs. For instance, in order to draw points, we have a prefab for a point, which is instantiated each time we click on screen. We need to do something similar for the lines. A line prefab is already created and maped to the script in the linePrefab variable. So we only need to instantiate the prefab.
// - TODO 1.1 Instantiate linePrefab
GameObject line = Instantiate(linePrefab, hit.Pose.position, hit.Pose.rotation);
2. Then, we need to place the line between the two points. In order to do that, first of all we need to place the prefab at the same distance between the two points. A 3D point has three coordinates in order to be placed in space. So we need to compute all the three coordinates for the line. The formula is the same for ox, oy and oz axis so let's see only for one axis how the formula works. Let's say we have point A on position 3 and point B position 5. It's obvious for us that the middle of this line would be on 4. But how do we compute this number? Well, we take the first point and add to it half the difference between the two points. To be more specific: middle = pointA + (pointB -pointA) / 2 = 3 + (5 - 3) / 2 = 3 + 2 / 2 = 3 + 1 = 4.
// - TODO 1.2 Set position at half the distance between the last two added points
line.transform.position = new Vector3(points[points.Count - 1].transform.position.x
+ (points[points.Count - 2].transform.position.x
- points[points.Count - 1].transform.position.x) / 2,
points[points.Count - 1].transform.position.y
+ (points[points.Count - 2].transform.position.y
- points[points.Count - 1].transform.position.y) / 2,
points[points.Count - 1].transform.position.z
+ (points[points.Count - 2].transform.position.z
- points[points.Count - 1].transform.position.z) / 2);
3. Now, we need to make the line long enough. To start from one point and to end on the other point. For this, we will use the distance function, which gives me the distance between two points.
// - TODO 1.3 Set scale: two fixed numbers on ox and oy axis, the distance between the two points on oz axis
line.transform.localScale = new Vector3(0.01f, 0.01f, Vector3.Distance(points[points.Count - 1].transform.position,
points[points.Count - 2].transform.position)); // !0.005 can be changed to whatever value we want
4. Lastly, we need to fix the line in place, to be stable and not shaky. For this, we need to attach an anchor to our line (as you have seen in HelloAR example).
// - TODO 1.4 Set anchor so that the line will not move - SOLVE THIS AFTER TESTING 1.1 - 1.3 AND NOTICE THE DIFFERENCES
line.transform.parent = anchor.transform;
Compute Distance between two Points
Now we need to compute and display on screen the distance between two points. We will need to update the lines 207 - 222 and 130 - 134. For this, we need to do the following steps:
1. Compute the distance between the last two added points. The formula for the distance between two 3D points A and B is the following: distance = sqrt((B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y) + (B.z - A.z) * (B.z - A.z)). The formula is already in code, but we need to compute deltaX, deltaY and deltaZ: deltaX = B.x - A.x;
// - TODO 2.1 Compute distance between the two last added points
float deltaX = points[points.Count - 1].transform.position.x - points[points.Count - 2].transform.position.x;
float deltaY = points[points.Count - 1].transform.position.y - points[points.Count - 2].transform.position.y;
float deltaZ = points[points.Count - 1].transform.position.z - points[points.Count - 2].transform.position.z;
float distance = (float)Mathf.Sqrt(deltaX * deltaX + deltaY * deltaY + deltaZ * deltaZ);
2. Display the distance on screen. We have computed the distance. It is saved in a float variable. But in order to display it on screen, we need to convert it to string.
// - TODO 2.2 Add the distance to our distances list
partialDistance.text = distance.ToString();
3. Fix the text on screen. Before you solve this step, comment line 133 and test the result. If the code remains like this, once we place the text on screen, it will stay fixed on screen annd not near the line we have drawn. For instance, if we move the phone camera and the line is behind us, the text should also be behind us and, as a result, not displayed on screen. But at this step, the text stays fixed on screen, it does not follow the line. In order to fix this we need to update line 133. First of all, we need the position of the line.. Then, we need to convert this 3D position from the real world to a 2D position from the screen.
// The distance between two points needs to be always placed near the two points.
// If we move the phone screen the text will also move (the text is fixed on canvas
// ant the canvas always follows the phone screen),
// so we need to update the position on screen for each distance displayed
for (int i = 0; i < distances.Count; i++)
{
// TODO 2.3 Update text position - SOLVE THIS AFTER TESTING 2.1 - 2.2 AND NOTICE THE DIFFERENCES
distances[i].transform.position = Camera.main.WorldToScreenPoint(new Vector3(points[i].transform.position.x, points[i].transform.position.y, points[i].transform.position.z));
}
Compute total Distance
Finally, we need to display the total distance on screen (lines 224 - 226).
1. We need to add the previously computed distance to the total distance. Then, we need to convert the total distance from a number to a string.
// TODO 3.1 Update total distance
distanceSum = = distanceSum + distance;;
totalDistance.text = "Total distance: " + distanceSum.ToString();