0
1
00:00:00,600 --> 00:00:09,000
Now, in the last lesson, we captured, processed, and incorporated our tracking image into our Xcode project
1

2
00:00:09,690 --> 00:00:16,740
and we added it to our configuration so that it knows what are the images that it should be detecting.
2

3
00:00:16,740 --> 00:00:23,070
Now, in this lesson, I want to show you how we can start recognizing those images using ARKit and how
3

4
00:00:23,070 --> 00:00:30,730
to turn the image into a plane that we're going to later use to set our 3D models on.
4

5
00:00:30,750 --> 00:00:37,110
So first things first, we're gonna be working within the ARSCNViewDelegate methods section, but
5

6
00:00:37,110 --> 00:00:41,140
we're going to delete all of these other methods because we're not going to be using it.
6

7
00:00:41,160 --> 00:00:46,040
Make sure you don't delete the last one because that's needed for the entire class.
7

8
00:00:46,080 --> 00:00:54,900
Now, the method that we're gonna add in here is called renderer nodeFor anchor. And this one asked the
8

9
00:00:54,900 --> 00:01:01,310
delegate to provide a SceneKit node corresponding to a newly added anchor.
9

10
00:01:01,320 --> 00:01:06,270
Now, if you remember from previous lessons, the anchor is the thing that was detected.
10

11
00:01:06,330 --> 00:01:13,680
So in our case, the anchor will be the image that got detected on screen, and the node is going to be
11

12
00:01:13,680 --> 00:01:18,510
a 3D object that we're going to provide in response to detecting the anchor,
12

13
00:01:18,900 --> 00:01:23,720
so that's basically what this method is all about. When the image gets detected,
13

14
00:01:23,760 --> 00:01:30,930
this method will get called and we can look at the image that got detected. And in response, we can provide
14

15
00:01:30,960 --> 00:01:35,040
a 3D object to be rendered into the screen.
15

16
00:01:35,160 --> 00:01:40,380
Now, the first thing we're going to do is we're going to create that brand-new 3D object or what we call
16

17
00:01:40,470 --> 00:01:47,410
a SCNNode. So this is our new node object.
17

18
00:01:47,540 --> 00:01:55,400
And once everything's all said and done, then we're going to return this node as the output of this method.
18

19
00:01:55,850 --> 00:01:56,470
As you can see,
19

20
00:01:56,470 --> 00:02:04,100
this method is expecting a output of SCNNode and it needs to send that back onto the scene so that
20

21
00:02:04,100 --> 00:02:07,310
it can render a 3D object.
21

22
00:02:07,400 --> 00:02:13,610
Now, in between these two lines of code is everything that we need to do to set up our plane and also
22

23
00:02:13,610 --> 00:02:15,560
render our 3D models.
23

24
00:02:15,560 --> 00:02:20,890
So first things first, we're going to check to see if the anchor that we detected,
24

25
00:02:20,900 --> 00:02:27,040
so if the item that was detected in the world was in fact an ARImageAnchor.
25

26
00:02:27,080 --> 00:02:29,220
So we're going to do a type check.
26

27
00:02:29,240 --> 00:02:32,450
So let's say let imageAnchor
27

28
00:02:34,950 --> 00:02:40,230
= anchor, and that, of course, comes from here.
28

29
00:02:40,530 --> 00:02:45,540
And we're going to check if the data type is an ARImageAnchor.
29

30
00:02:46,680 --> 00:02:52,890
And this, of course, contains information about the position and orientation of an image detected in the
30

31
00:02:53,020 --> 00:02:54,120
ARSession.
31

32
00:02:54,750 --> 00:03:03,130
If a detected, say, a plane or a point or anything else, then this is not going to carry out.
32

33
00:03:03,270 --> 00:03:08,730
In that case, we can use this with a "if let" to only carry out code
33

34
00:03:09,180 --> 00:03:14,190
if the anchor that was detected is in fact of data type ARImageAnchor.
34

35
00:03:14,340 --> 00:03:17,900
So it was in fact an image that got detected.
35

36
00:03:17,910 --> 00:03:25,170
Now, if that is true, then we're going to create a new plane using that image, and the plane is going be
36

37
00:03:25,170 --> 00:03:29,160
created as we did before using SCNPlane,
37

38
00:03:29,480 --> 00:03:33,920
and we're going to use the method that provides a width and a height.
38

39
00:03:33,930 --> 00:03:39,090
Now, this plane is going to be created from the image that was detected,
39

40
00:03:39,090 --> 00:03:46,200
so from our Pokémon card. And we want the width and height of the plane in the physical world to be the
40

41
00:03:46,200 --> 00:03:48,020
same as it is,
41

42
00:03:48,030 --> 00:03:48,330
right?
42

43
00:03:48,360 --> 00:03:53,060
So we want it to be exactly the size that our card is.
43

44
00:03:53,130 --> 00:04:00,420
Now, I can either provide in hard values that I've measured using a tape measure, or I can simply say
44

45
00:04:00,870 --> 00:04:07,920
look at the imageAnchor that you found and look at the referenceImage that it contains, and then get
45

46
00:04:07,980 --> 00:04:13,440
its physical size, and grab the width property.
46

47
00:04:13,620 --> 00:04:20,310
That means that it's going to look at the image that it detected and try to measure its actual physical
47

48
00:04:20,310 --> 00:04:28,830
size and get all of its height and width properties to put in here, instead of me having to hardcode it.
48

49
00:04:28,970 --> 00:04:37,510
So once we've got a dimension to our plane, then we're going to use it to create a planeNode, and this
49

50
00:04:37,510 --> 00:04:44,800
is going to be the 3D object that we're going to render just on top of our card so that we can tell
50

51
00:04:44,800 --> 00:04:46,950
that our card has been recognized.
51

52
00:04:46,990 --> 00:04:53,290
So the planeNode is going to be an SCNNode and it's going to be created with a geometry. And the
52

53
00:04:53,290 --> 00:05:02,220
geometry is, of course, this plane that we created over here. And now, we can tap into this node that we
53

54
00:05:02,220 --> 00:05:09,970
created earlier on and we can add a childNode which is going to be our planeNode.
54

55
00:05:10,350 --> 00:05:15,780
So, now let's hit run and let's see what we get when we tried to detect our card.
55

56
00:05:18,400 --> 00:05:24,400
When you run the app, you'll be asked to grant access to the camera so that we can start an 
56

57
00:05:24,400 --> 00:05:25,480
ARSession.
57

58
00:05:25,480 --> 00:05:32,740
And once it has, then we can reveal the face of our card which is meant to be detected and you can see
58

59
00:05:32,740 --> 00:05:36,760
that we're getting this plane that's being rendered on top of it.
59

60
00:05:36,970 --> 00:05:42,610
Now, the only problem with this plane is that it's being rendered vertically, whereas what we actually
60

61
00:05:42,610 --> 00:05:48,620
want is for it to be lying down with the same dimension as our card.
61

62
00:05:48,640 --> 00:05:55,120
So in order to do that, we have to do a few transformations. Now, the transformation we need to make is
62

63
00:05:55,120 --> 00:06:06,520
to rotate this plane that we've created by 90 degrees, anticlockwise in the x axis.
63

64
00:06:06,520 --> 00:06:13,630
So here are our three axis: x, y, and Z. And currently, our card looks like this.
64

65
00:06:13,630 --> 00:06:22,210
So along the x axis, we're going to rotate it anticlockwise. And to do that, all we have to do is to take
65

66
00:06:22,210 --> 00:06:32,480
the planeNode and tap into the eulerAngles, which is the node orientation, and notice that it's expressed
66

67
00:06:32,690 --> 00:06:34,220
in radians,
67

68
00:06:34,220 --> 00:06:42,830
so that requires the use of pi. And the eulerAngle that we're going to change is the x or the first
68

69
00:06:42,830 --> 00:06:44,330
component.
69

70
00:06:44,330 --> 00:06:50,000
And in order to rotate anticlockwise, then I'm going to make it negative.
70

71
00:06:50,000 --> 00:06:56,120
And the amount that I want to rotate it by is only 90 degrees. So in radians,
71

72
00:06:56,120 --> 00:07:05,120
that's expressed as pi divided by 2. Half a pi is 90 degrees in radians.
72

73
00:07:05,120 --> 00:07:11,060
And you have to make sure that there's no space between the minus and the dot pi.
73

74
00:07:11,060 --> 00:07:18,620
Now, you can also write pi as Float.pi or you can simply use the shorthand way which simply assumes
74

75
00:07:18,620 --> 00:07:24,780
that it's a float and we're tapping into the constant of pi.
75

76
00:07:24,790 --> 00:07:32,720
So, now let's hit run again and see what happens this time.
76

77
00:07:32,720 --> 00:07:41,180
So, now you can see that this plane has been generated is now completely attached to the dimension of
77

78
00:07:41,180 --> 00:07:45,170
the card, and it is flush with the surface of the card.
78

79
00:07:45,620 --> 00:07:54,650
And this gives us a perfect place to start projecting 3D images onto, and for 3D images to be tracked.
79

80
00:07:54,680 --> 00:07:56,290
Now, there's just one thing.
80

81
00:07:56,360 --> 00:08:02,270
Once we've got the plane show up, it's completely white and completely opaque. And we can't really see
81

82
00:08:02,270 --> 00:08:03,620
our card anymore,
82

83
00:08:03,740 --> 00:08:09,380
which means I don't really know what was on the card, so it would be really nice if I can make this plane
83

84
00:08:09,500 --> 00:08:12,110
a little bit more transparent.
84

85
00:08:12,350 --> 00:08:20,980
So let's give that a go. Now, in order to make our plane transparent, before we set the geometry,
85

86
00:08:21,120 --> 00:08:29,700
we can set another one of its properties which is its material and it's diffuse. So we can say
86

87
00:08:29,850 --> 00:08:42,610
plane.firstMaterial.diffuse.contents = UIColor that is created using this method.
87

88
00:08:42,660 --> 00:08:45,420
These are the grayscale and the alpha values.
88

89
00:08:45,810 --> 00:08:46,840
So the grayscale,
89

90
00:08:46,860 --> 00:08:50,950
I'll leave it as completely white. And the alpha,
90

91
00:08:51,190 --> 00:08:57,670
I'll change that to 0.5 so that it's half as transparent as it used to be.
91

92
00:08:57,970 --> 00:09:04,770
And let's try that out.
92

93
00:09:04,810 --> 00:09:13,000
So, now you can see that the plane is rendered on top of my Pokémon card, but it's also transparent so
93

94
00:09:13,000 --> 00:09:18,030
that I can see through it into my actual card.
94

95
00:09:18,070 --> 00:09:26,200
So, now we're at the position when we are ready to start rendering our 3D Eevee on top of this playing card
95

96
00:09:26,740 --> 00:09:35,800
and using that plane to track and render the 3D model, and to move the 3D model as I move this physical
96

97
00:09:35,800 --> 00:09:37,120
card.
97

98
00:09:37,300 --> 00:09:39,880
That is what we're going to be learning in the next lesson.
98

99
00:09:40,240 --> 00:09:42,850
So for all of that and more, I'll see you there.
