WEBVTT 1 00:00:23.799 --> 00:00:26.649 Let's learn about VR lenses 2 00:00:26.649 --> 00:00:28.844 which operate on different principles 3 00:00:28.844 --> 00:00:31.094 from monitor displays 4 00:00:31.094 --> 00:00:33.388 and how to use Widget Components 5 00:00:33.388 --> 00:00:35.338 to convert screen-based UI 6 00:00:35.338 --> 00:00:37.064 into World UI format 7 00:00:37.064 --> 00:00:41.335 Next, let's implement the effect of clicking buttons on a World UI Widget 8 00:00:41.335 --> 00:00:43.885 using the VR controller 9 00:00:43.885 --> 00:00:46.456 like a remote control 10 00:00:46.456 --> 00:00:50.675 Additionally, let's learn how to apply curved UI 11 00:00:50.675 --> 00:00:53.885 to address visibility issues 12 00:00:53.885 --> 00:00:56.646 caused by the wide 13 00:00:56.646 --> 00:00:58.860 and free viewing angle unique to VR 14 00:00:59.272 --> 00:01:02.974 Create a widget 15 00:01:03.259 --> 00:01:04.300 Hello 16 00:01:04.300 --> 00:01:06.500 today we will be creating 17 00:01:06.500 --> 00:01:08.815 a VR widget 18 00:01:08.815 --> 00:01:11.015 If we've previously created widgets while making other content 19 00:01:11.015 --> 00:01:14.210 many of you might be wondering 20 00:01:14.210 --> 00:01:17.610 what will be different 21 00:01:17.610 --> 00:01:19.625 when creating widgets for VR 22 00:01:19.625 --> 00:01:22.258 Generally, when we create widgets 23 00:01:22.258 --> 00:01:25.724 we use an overlay method 24 00:01:25.724 --> 00:01:29.086 to draw the widget on top of the World 25 00:01:29.086 --> 00:01:32.943 It was drawn to fit the size of the screen 26 00:01:32.943 --> 00:01:36.494 but in the case of VR, it's not a fixed monitor 27 00:01:36.494 --> 00:01:39.344 When we move our head 28 00:01:39.344 --> 00:01:42.003 the camera moves 29 00:01:42.003 --> 00:01:45.964 so drawing on top of it can result in the widget not appearing as intended on the screen 30 00:01:45.964 --> 00:01:49.845 Therefore, in VR 31 00:01:49.845 --> 00:01:53.072 we use World Widgets and different widget pointer interactions to manipulate buttons 32 00:01:53.072 --> 00:01:58.499 which involves some additional steps 33 00:01:58.499 --> 00:02:01.697 Also, because our field of view is wider in VR 34 00:02:01.697 --> 00:02:04.397 there may be UI elements 35 00:02:04.397 --> 00:02:07.010 that are not easily visible within our field of view 36 00:02:07.010 --> 00:02:10.310 so we need to represent the widgets in a slightly curved display format 37 00:02:10.310 --> 00:02:14.394 rather than a flat plane 38 00:02:14.394 --> 00:02:17.858 So, despite several somewhat cumbersome procedures 39 00:02:17.858 --> 00:02:22.290 in VR, we have to consider that due to the nature of VR device mechanisms 40 00:02:22.290 --> 00:02:24.240 we have no choice 41 00:02:24.240 --> 00:02:26.116 but to draw in that way 42 00:02:26.116 --> 00:02:29.166 I'll explain the principle of drawing UI on VR devices 43 00:02:29.166 --> 00:02:33.627 while showing you from behind 44 00:02:33.627 --> 00:02:36.627 Alright, continuing from last time 45 00:02:36.627 --> 00:02:39.978 this session we'll create a widget together 46 00:02:39.978 --> 00:02:43.960 Let's start by creating a basic widget then 47 00:02:43.960 --> 00:02:49.010 Go to the Contents folder 48 00:02:49.010 --> 00:02:50.690 then click Add → New Folder to create a new folder 49 00:02:50.690 --> 00:02:55.465 Name the folder 'UI' 50 00:02:55.465 --> 00:02:57.732 Inside this UI folder 51 00:02:57.732 --> 00:03:03.232 right-click and go to User Interface → Widget Blueprint 52 00:03:03.232 --> 00:03:06.035 to add a new Widget Blueprint 53 00:03:06.045 --> 00:03:10.143 Select User Widget as the parent class 54 00:03:10.143 --> 00:03:16.624 So, I'll create a widget file 55 00:03:16.624 --> 00:03:20.063 named WBP_MainWidget 56 00:03:20.063 --> 00:03:24.846 Double-click to open the settings window 57 00:03:24.846 --> 00:03:27.030 First and foremost 58 00:03:27.030 --> 00:03:28.440 we'll need a canvas, right? 59 00:03:28.440 --> 00:03:31.192 So, we'll add a canvas panel 60 00:03:36.316 --> 00:03:39.657 And then we'll add a text block 61 00:03:39.657 --> 00:03:42.143 to this canvas panel 62 00:03:42.143 --> 00:03:44.509 Add a text block to the canvas panel 63 00:03:44.509 --> 00:03:49.232 Set the anchor of this text block to be centered 64 00:03:52.093 --> 00:03:56.582 Setting the alignment to (0.5, 0.5) 65 00:03:56.582 --> 00:04:00.162 centers the pivot 66 00:04:00.162 --> 00:04:02.568 so placing it at (0, 0) 67 00:04:02.568 --> 00:04:05.736 will position it in the center, like this 68 00:04:05.736 --> 00:04:08.004 I'll increase the size a bit 69 00:04:08.004 --> 00:04:10.321 Just adjust it to fit the font size, right? 70 00:04:10.321 --> 00:04:14.905 I'll make the font stand out more by setting it to about 40% 71 00:04:15.964 --> 00:04:18.658 The content of the first text 72 00:04:18.658 --> 00:04:21.908 will be named 73 00:04:21.908 --> 00:04:23.423 "Select Move Type" 74 00:04:31.886 --> 00:04:36.136 Set the font justification to center 75 00:04:36.136 --> 00:04:39.481 so that it aligns centrally 76 00:04:39.481 --> 00:04:42.332 I'll express the text in a noticeable yellow color 77 00:04:42.332 --> 00:04:44.293 to make it stand out 78 00:04:47.927 --> 00:04:53.427 Then let's set the size to around 500 width 79 00:04:53.427 --> 00:04:58.273 and 80 to 70 height 80 00:04:58.273 --> 00:05:03.075 So, set it to around 500 width and 70 height 81 00:05:03.075 --> 00:05:09.332 Place it slightly above like this from the top 82 00:05:09.332 --> 00:05:14.682 Set X to 0 and Y 83 00:05:14.682 --> 00:05:18.332 to approximately -350 for positioning 84 00:05:22.540 --> 00:05:25.758 And below that, we'll place the buttons 85 00:05:25.758 --> 00:05:28.807 We'll place one button on the canvas 86 00:05:28.807 --> 00:05:33.302 We'll add a text inside this button 87 00:05:33.302 --> 00:05:36.906 I'll add a text block like this as a child of the button 88 00:05:36.906 --> 00:05:40.639 inside its hierarchy 89 00:05:40.639 --> 00:05:49.738 The first text will be named "Normal Move" 90 00:05:49.738 --> 00:05:52.588 The font size will be the same, 40 91 00:05:52.588 --> 00:05:58.560 The color will be set to a yellow shade like this 92 00:06:01.114 --> 00:06:04.114 The alignment will be set to center alignment like this 93 00:06:11.143 --> 00:06:13.569 Next, the button's name 94 00:06:17.252 --> 00:06:23.955 will be "Button_NormalMove" 95 00:06:23.955 --> 00:06:28.228 So, check the "Is Variable" option for it 96 00:06:28.228 --> 00:06:32.355 It's best to adjust the button's size to fit the text perfectly 97 00:06:32.355 --> 00:06:36.965 Set the anchor to center first 98 00:06:36.965 --> 00:06:47.867 then a size of approximately 400 width and 70 height should be sufficient 99 00:06:47.867 --> 00:06:51.817 I'll set the background color 100 00:06:51.817 --> 00:06:56.094 to a slightly reddish hue like this 101 00:06:56.094 --> 00:06:59.867 Let's place this button here 102 00:07:03.223 --> 00:07:08.213 Set its alignment to 0.5, 0.5 for center alignment 103 00:07:08.213 --> 00:07:12.221 with X at 0 and Y 104 00:07:12.221 --> 00:07:13.589 at around -150 105 00:07:16.174 --> 00:07:19.332 If the button seems a bit too low, let's reduce its height a bit more, shall we? 106 00:07:21.263 --> 00:07:25.381 Let's leave it like this for now and proceed 107 00:07:25.381 --> 00:07:27.134 Since there might be more buttons 108 00:07:30.144 --> 00:07:34.540 let's duplicate it by pressing Ctrl+D 109 00:07:34.540 --> 00:07:38.312 Then, set the position with X at 0 110 00:07:38.312 --> 00:07:40.540 and Y around 0 111 00:07:40.540 --> 00:07:42.590 to place it approximately in the center 112 00:07:42.590 --> 00:07:45.540 So, let's name the text 113 00:07:47.952 --> 00:07:53.664 inside it "Teleport Move" 114 00:07:53.668 --> 00:07:56.759 I'll add another button 115 00:07:56.759 --> 00:07:58.769 to display the text "Teleport Move" 116 00:08:03.765 --> 00:08:04.720 Next 117 00:08:06.515 --> 00:08:09.732 the function of this button will be 118 00:08:09.732 --> 00:08:11.371 when you select this button 119 00:08:11.371 --> 00:08:12.989 it will use the Normal Move function 120 00:08:12.990 --> 00:08:13.990 we created last time 121 00:08:13.990 --> 00:08:16.526 for movement 122 00:08:16.526 --> 00:08:18.783 If you select "Teleport Move" 123 00:08:21.302 --> 00:08:24.267 the movement method will change to teleportation mode 124 00:08:24.267 --> 00:08:26.733 implementing this functionality in the UI 125 00:08:26.733 --> 00:08:28.936 First, let's compile and save 126 00:08:30.703 --> 00:08:32.707 To implement this functionality 127 00:08:32.707 --> 00:08:36.044 we need to access the movement method 128 00:08:36.044 --> 00:08:38.787 from the HunetVRPlayer phone 129 00:08:38.787 --> 00:08:44.242 This involves accessing the movement method from the HunetVRPlayer phone 130 00:08:44.242 --> 00:08:47.291 where we had teleportation and normal movement methods 131 00:08:47.291 --> 00:08:50.539 under Thumbstick Axis Right 132 00:08:50.539 --> 00:08:54.024 We'll add another boolean variable 133 00:08:54.024 --> 00:08:56.424 to branch out using Branch and choose between the two methods 134 00:08:56.424 --> 00:08:58.064 teleportation and normal movement 135 00:08:58.064 --> 00:09:01.113 under Thumbstick Axis Right 136 00:09:01.113 --> 00:09:04.192 Press the "+" button 137 00:09:04.192 --> 00:09:06.915 under VARIABLES to add a new variable 138 00:09:06.915 --> 00:09:11.515 I'll create a variable 139 00:09:11.515 --> 00:09:13.074 named "Use Teleport" 140 00:09:13.074 --> 00:09:15.737 I'll change the data type to Boolean 141 00:09:15.737 --> 00:09:17.287 so it can accept 142 00:09:17.287 --> 00:09:18.539 True/False values 143 00:09:21.361 --> 00:09:23.450 Let me compile it briefly 144 00:09:23.450 --> 00:09:27.697 and set the default value to False 145 00:09:27.697 --> 00:09:29.896 I'll set the initial state to False 146 00:09:33.182 --> 00:09:37.173 Bring in "Use Teleport" 147 00:09:37.173 --> 00:09:38.905 to create a branch 148 00:09:42.182 --> 00:09:43.925 based on it 149 00:09:43.925 --> 00:09:48.935 Use the Branch node 150 00:09:48.935 --> 00:09:52.539 to execute the Draw Teleport Line function when Triggered 151 00:09:52.539 --> 00:09:56.856 if Use Teleport is True 152 00:09:56.856 --> 00:10:01.172 If Use Teleport is False 153 00:10:01.172 --> 00:10:03.410 execute Normal Move in this manner 154 00:10:03.410 --> 00:10:05.110 Next 155 00:10:05.110 --> 00:10:06.757 connect the Action Value to here 156 00:10:10.885 --> 00:10:13.539 Then, similarly 157 00:10:13.539 --> 00:10:15.886 when it's completed 158 00:10:15.886 --> 00:10:20.311 add another Branch node here because it needs to be done again 159 00:10:20.311 --> 00:10:22.272 So, when it's completed 160 00:10:22.272 --> 00:10:24.737 set the condition to "Use Teleport" 161 00:10:27.321 --> 00:10:30.123 If it's true in the Branch node when completed 162 00:10:31.806 --> 00:10:34.539 perform the Teleport Action 163 00:10:38.539 --> 00:10:42.945 Next, duplicate it by pressing Ctrl+D 164 00:10:42.945 --> 00:10:47.281 and if it is False, set it to perform a Normal Move 165 00:10:47.281 --> 00:10:48.431 Then, I'll pass the Input Value 166 00:10:48.431 --> 00:10:50.282 here as well 167 00:10:55.143 --> 00:10:56.876 I will use line sorting 168 00:11:03.945 --> 00:11:08.628 I will adjust the position to achieve this look 169 00:11:15.133 --> 00:11:17.499 Compile, Save 170 00:11:17.499 --> 00:11:20.786 Then, the actual movement will change according to this value, right? 171 00:11:20.786 --> 00:11:23.371 Let's test it first 172 00:11:26.737 --> 00:11:31.024 For now, it's in a False state 173 00:11:31.024 --> 00:11:35.509 In the False state, when you press Play 174 00:11:42.420 --> 00:11:45.143 you can see that it moves forward and backward 175 00:11:45.143 --> 00:11:46.743 with the basic Normal Move 176 00:11:46.743 --> 00:11:47.727 right? 177 00:11:50.539 --> 00:11:52.064 However 178 00:11:54.242 --> 00:11:56.692 I will change the variable value of Use Teleport 179 00:11:56.692 --> 00:11:58.975 from False to True 180 00:11:58.975 --> 00:12:00.564 then compile and save it 181 00:12:00.564 --> 00:12:01.539 before testing once more 182 00:12:05.024 --> 00:12:07.965 Then, when moving 183 00:12:07.965 --> 00:12:10.509 you'll see the Teleport line drawn 184 00:12:10.509 --> 00:12:14.453 confirming that it moves in the direction of Teleport 185 00:12:14.453 --> 00:12:15.331 right? 186 00:12:21.648 --> 00:12:26.588 This does not have exception handling for grabbing 187 00:12:26.588 --> 00:12:29.123 but while we're at it, you confirmed that this works well 188 00:12:29.123 --> 00:12:31.539 While we're at it 189 00:12:31.539 --> 00:12:34.727 I'll try adding exception handling for grabbing when it's not handled yet 190 00:12:34.727 --> 00:12:38.301 When performing Grab Action or Release Action 191 00:12:38.301 --> 00:12:44.895 you should only grab the object when there is no actor currently grabbed 192 00:12:44.895 --> 00:12:47.539 So, here before the Grab Action 193 00:12:50.539 --> 00:12:52.599 you'll first use the Is Valid function on CurrentGrabbedActor 194 00:12:56.539 --> 00:12:58.549 to check 195 00:12:58.549 --> 00:13:02.361 whether there is a value 196 00:13:02.361 --> 00:13:05.856 or not 197 00:13:05.856 --> 00:13:09.747 When the value is not present 198 00:13:09.747 --> 00:13:12.014 using Is Not Valid 199 00:13:14.331 --> 00:13:16.915 let's neatly organize it to take action to grab the object 200 00:13:19.351 --> 00:13:21.183 On the other hand, when releasing 201 00:13:23.034 --> 00:13:25.103 When releasing with Release Action 202 00:13:25.103 --> 00:13:27.331 you should detach 203 00:13:27.331 --> 00:13:30.797 only when there is a Grabbed Actor 204 00:13:30.797 --> 00:13:35.381 present 205 00:13:35.381 --> 00:13:39.984 Add an Is Valid node to 206 00:13:42.777 --> 00:13:47.737 so that Detach is performed 207 00:13:47.737 --> 00:13:51.004 only when there is something being held (Grabbed Actor) 208 00:13:51.004 --> 00:13:55.361 and Is Valid is true 209 00:13:55.361 --> 00:13:59.995 So, now even if there's no object 210 00:13:59.995 --> 00:14:04.598 and you attach and detach, there won't be any errors 211 00:14:04.598 --> 00:14:07.371 Therefore, recognizing the importance of such exception handling 212 00:14:07.371 --> 00:14:10.044 is crucial 213 00:14:10.044 --> 00:14:13.143 Alright, let's switch back to the Widget 214 00:14:13.143 --> 00:14:16.678 and return to the Widget Blueprint 215 00:14:16.678 --> 00:14:21.292 We already know that 216 00:14:21.292 --> 00:14:25.539 depending on whether the player's variable Use Teleport 217 00:14:25.539 --> 00:14:28.658 is True or False 218 00:14:28.658 --> 00:14:29.777 the movement method changes accordingly 219 00:14:30.412 --> 00:14:34.213 For creating 220 00:14:34.470 --> 00:14:37.232 a World-type UI 221 00:14:37.232 --> 00:14:39.638 we'll have the player 222 00:14:39.638 --> 00:14:44.608 create this Widget 223 00:14:44.608 --> 00:14:46.311 Let's switch to the Event Graph tab 224 00:14:46.311 --> 00:14:50.034 and turn off other function nodes like this 225 00:14:50.034 --> 00:14:53.489 When we start 226 00:14:53.489 --> 00:14:55.301 at the BeginPlay event 227 00:14:55.301 --> 00:14:59.163 we'll create a Widget here 228 00:14:59.163 --> 00:15:03.172 Here, from the execution pin of the SET node 229 00:15:03.172 --> 00:15:07.172 drag to create a Widget 230 00:15:07.172 --> 00:15:09.351 and make one 231 00:15:09.351 --> 00:15:10.569 The Widget we're creating 232 00:15:10.569 --> 00:15:14.905 will be named WBP_MainWidget 233 00:15:21.034 --> 00:15:23.658 Just to be safe 234 00:15:23.658 --> 00:15:25.958 I'll store this value 235 00:15:25.958 --> 00:15:27.222 as a variable using "Promote to variable" 236 00:15:27.222 --> 00:15:28.549 So, I'll name this variable 237 00:15:30.885 --> 00:15:36.489 MainWidget_instance 238 00:15:36.489 --> 00:15:38.539 Since it's already created, it's an instance now 239 00:15:42.093 --> 00:15:44.539 You can see that the variable has been created here 240 00:15:49.945 --> 00:15:52.539 Then, we need to implement the functionality of the buttons 241 00:15:52.539 --> 00:15:54.985 so we'll pass the owner 242 00:15:54.985 --> 00:15:58.539 which is the VR player 243 00:15:58.539 --> 00:16:01.539 to this Widget 244 00:16:01.539 --> 00:16:05.390 So 245 00:16:05.390 --> 00:16:08.143 let's go to the MainWidget 246 00:16:08.143 --> 00:16:09.643 click on the Graph tab 247 00:16:09.643 --> 00:16:11.291 and switch to the Graph tab 248 00:16:11.291 --> 00:16:14.935 Here, in the My Blueprint panel 249 00:16:14.935 --> 00:16:19.539 under VARIABLES, click the + button 250 00:16:19.539 --> 00:16:23.539 to create a new variable named Player 251 00:16:23.539 --> 00:16:26.301 And the data type of this variable 252 00:16:26.301 --> 00:16:31.004 will be BP_HunetVRPlayer 253 00:16:31.004 --> 00:16:35.123 Let's set it to be of 254 00:16:35.123 --> 00:16:36.678 type Object Reference for VRPlayer 255 00:16:39.338 --> 00:16:41.806 Compile and save it 256 00:16:41.806 --> 00:16:45.083 Now, let's go back to the VRPlayer side 257 00:16:45.083 --> 00:16:49.707 When we initially create this Widget 258 00:16:49.707 --> 00:16:55.271 we have the Player variable here 259 00:16:55.271 --> 00:16:56.757 Set Player 260 00:17:04.489 --> 00:17:08.045 Here, we'll pass in self (or "this") as the Player variable 261 00:17:08.045 --> 00:17:09.599 Self 262 00:17:09.599 --> 00:17:12.292 We'll get a reference to self 263 00:17:12.292 --> 00:17:13.798 and then pass that reference here 264 00:17:13.798 --> 00:17:17.540 So, the Widget will now have 265 00:17:17.540 --> 00:17:20.134 the information about its owner 266 00:17:20.134 --> 00:17:22.372 the Player, once it's created 267 00:17:30.005 --> 00:17:32.787 So, to see 268 00:17:32.787 --> 00:17:37.194 how the Widget appears 269 00:17:37.194 --> 00:17:38.847 let's check this value 270 00:17:42.055 --> 00:17:44.540 in the MainWidget Instance 271 00:17:44.540 --> 00:17:46.164 In the MainWidget Instance 272 00:17:46.164 --> 00:17:51.124 let's use Add to Viewport to display it 273 00:17:51.124 --> 00:17:52.424 following the method 274 00:17:52.424 --> 00:17:55.797 we've used before 275 00:17:55.797 --> 00:17:57.094 with Add to Viewport 276 00:17:57.094 --> 00:17:59.045 I'll add a Reroot node here to tidy up the lines 277 00:17:59.045 --> 00:18:04.916 as they're getting a bit complex 278 00:18:04.916 --> 00:18:05.996 Should we do it like this? 279 00:18:13.183 --> 00:18:19.540 Let's add another Reroot node here 280 00:18:19.540 --> 00:18:22.540 to make it more organized and easier to view like this 281 00:18:22.540 --> 00:18:25.114 Then, when we initially start 282 00:18:25.114 --> 00:18:26.778 the Widget should be displayed like this 283 00:18:26.778 --> 00:18:30.699 When you press Play, the Widget should be displayed 284 00:18:30.699 --> 00:18:35.926 but currently, it's not showing up 285 00:18:35.926 --> 00:18:40.352 even though the Widget should be visible on the screen 286 00:18:40.352 --> 00:18:43.124 I'll explain why the Widget isn't displaying 287 00:18:43.124 --> 00:18:45.674 and the principles behind it 288 00:18:45.674 --> 00:18:49.724 This is explaining 289 00:18:49.724 --> 00:18:50.659 the traditional method of UI display 290 00:18:50.659 --> 00:18:53.540 Usually, we have a camera in the world 291 00:18:53.540 --> 00:18:57.005 that captures scenes either through a Projection or Orthographic method 292 00:18:57.005 --> 00:18:58.897 It captures everything 293 00:18:58.897 --> 00:19:02.540 within its view 294 00:19:02.540 --> 00:19:06.787 and converts it into an actual image 295 00:19:06.787 --> 00:19:09.312 That image is then rendered onto the actual screen, or monitor 296 00:19:09.312 --> 00:19:11.748 following this principle 297 00:19:11.748 --> 00:19:15.223 After capturing the image from the world as described 298 00:19:15.223 --> 00:19:17.540 we first render that world image onto the screen 299 00:19:17.540 --> 00:19:20.540 Then, we overlay the UI image 300 00:19:20.540 --> 00:19:22.840 on top of it 301 00:19:22.840 --> 00:19:24.678 So, in essence 302 00:19:24.678 --> 00:19:27.381 the later drawing (UI image) will be rendered on top of the earlier drawing (world image) 303 00:19:27.381 --> 00:19:30.362 effectively overlaying it 304 00:19:30.362 --> 00:19:34.758 This was the traditional method of UI rendering 305 00:19:34.758 --> 00:19:38.768 However, in the case of VR 306 00:19:38.768 --> 00:19:41.698 the method of rendering the screen is somewhat different 307 00:19:41.698 --> 00:19:45.560 So, here you can see it's labeled Left Eye, Right Eye 308 00:19:45.560 --> 00:19:47.194 In VR, there are separate cameras capturing images 309 00:19:47.194 --> 00:19:50.540 for the left and right eyes 310 00:19:50.540 --> 00:19:53.174 on the display 311 00:19:53.174 --> 00:19:56.055 The two captured images 312 00:19:56.055 --> 00:19:57.855 are then displayed 313 00:19:57.855 --> 00:20:00.055 within the VR device 314 00:20:00.055 --> 00:20:02.655 where each eye corresponds to a lens section 315 00:20:02.655 --> 00:20:06.320 There are separate lenses for the left and right eyes in VR devices 316 00:20:06.320 --> 00:20:10.970 Those lenses distort the slightly rectangular screen 317 00:20:10.970 --> 00:20:15.160 to give a sense of depth by slightly warping the image for each eye 318 00:20:15.160 --> 00:20:18.860 They pass through fisheye lenses 319 00:20:18.860 --> 00:20:21.240 that create a sense of depth by providing a stereoscopic effect, allowing for a sense of distance 320 00:20:21.240 --> 00:20:24.790 However, because the left and right eye lenses 321 00:20:24.790 --> 00:20:27.559 output different images 322 00:20:27.559 --> 00:20:30.059 we effectively see the same screen 323 00:20:30.059 --> 00:20:32.560 duplicated for both eyes 324 00:20:32.560 --> 00:20:36.260 With each lens angled slightly, around 5 degrees 325 00:20:36.260 --> 00:20:40.919 both lenses are projecting the current screen onto the VR display 326 00:20:40.919 --> 00:20:45.869 Therefore, if we were to draw the UI on the screen as usual 327 00:20:45.869 --> 00:20:49.469 actually 328 00:20:49.469 --> 00:20:52.269 since it's not drawn on the Screen World 329 00:20:52.269 --> 00:20:54.840 but on the entire area 330 00:20:54.840 --> 00:20:57.590 the UI ends up 331 00:20:57.590 --> 00:21:00.440 not being displayed 332 00:21:00.440 --> 00:21:02.119 at all 333 00:21:02.119 --> 00:21:05.019 So, even though we used Add to Viewport 334 00:21:05.019 --> 00:21:08.559 it actually wouldn't be drawn on the screen 335 00:21:08.559 --> 00:21:11.919 So, how should we go about solving this issue? 336 00:21:11.919 --> 00:21:16.369 In VR, you can't draw UI on the screen 337 00:21:16.369 --> 00:21:18.919 using the traditional viewport method like this 338 00:21:18.919 --> 00:21:22.719 You need to go with the method of creating 339 00:21:22.719 --> 00:21:25.120 and displaying UI objects in the world 340 00:21:25.120 --> 00:21:27.919 Then let's practice that once 341 00:21:27.919 --> 00:21:32.919 Then I'll first come over to the HunetVRPlayer 342 00:21:32.919 --> 00:21:35.956 So, for the existing part 343 00:21:35.956 --> 00:21:39.760 where you use Create Widget to insert 344 00:21:39.760 --> 00:21:42.519 I'll select all of it and press the Delete key to remove it 345 00:21:42.519 --> 00:21:45.219 Now, this type of screen-based widget 346 00:21:45.219 --> 00:21:49.080 cannot be used in VR 347 00:21:49.080 --> 00:21:51.480 So here in HunetVRPlayer 348 00:21:51.480 --> 00:21:53.400 if you press the Add button 349 00:21:53.400 --> 00:21:56.600 and select Widget 350 00:21:56.600 --> 00:21:58.480 there is a component called Widget 351 00:21:58.480 --> 00:22:05.279 Let's rename it to Main Widget 352 00:22:05.279 --> 00:22:10.441 and add the component here 353 00:22:10.441 --> 00:22:13.191 Next, if you go to the Details panel of this Main Widget 354 00:22:13.191 --> 00:22:16.180 you'll find a User Interface tab 355 00:22:16.180 --> 00:22:18.440 at the bottom 356 00:22:18.440 --> 00:22:23.119 Here, in the drawing space options between World and Screen 357 00:22:23.119 --> 00:22:25.000 we need to select World for our purposes 358 00:22:25.000 --> 00:22:27.919 So, let's choose to draw in the World space then 359 00:22:27.919 --> 00:22:32.240 Next, we'll create a Widget class 360 00:22:32.240 --> 00:22:33.390 that will generate 361 00:22:33.390 --> 00:22:36.890 our previously made 362 00:22:36.890 --> 00:22:39.240 WBP_MainWidget class 363 00:22:39.240 --> 00:22:42.399 Here, I see there's something called "Draw Size" 364 00:22:42.399 --> 00:22:46.366 If you set it up like this 365 00:22:46.366 --> 00:22:49.440 you'll see the widget floating in front of the player 366 00:22:49.440 --> 00:22:51.559 like this when you play 367 00:22:51.559 --> 00:22:54.039 But I think we had something like 368 00:22:54.039 --> 00:22:55.385 Selection Move Type 369 00:22:55.385 --> 00:22:57.399 up here 370 00:22:57.399 --> 00:23:01.039 and right now it looks a bit cropped or cut off 371 00:23:01.039 --> 00:23:03.436 If I were to reduce the Draw Size 372 00:23:03.436 --> 00:23:06.720 If you set it to 100 by 500, it would look like this 373 00:23:06.720 --> 00:23:11.279 If it's set to 100, the horizontal space might be too narrow, causing it to get cut off 374 00:23:11.279 --> 00:23:13.579 So, we should adjust it 375 00:23:13.579 --> 00:23:15.800 according to the Canvas Size 376 00:23:15.800 --> 00:23:17.410 Since we don't know the current Canvas Size 377 00:23:17.410 --> 00:23:18.880 let's go to WBP_MainWidget first 378 00:23:18.880 --> 00:23:24.240 and adjust the canvas in the Designer panel 379 00:23:24.240 --> 00:23:26.800 as it might be 380 00:23:26.800 --> 00:23:29.440 unnecessarily large 381 00:23:29.440 --> 00:23:32.190 So, let's adjust the Fill Screen option here 382 00:23:32.190 --> 00:23:34.062 to make it visible up to this extent 383 00:23:34.062 --> 00:23:38.180 We'll change the Fill Screen option 384 00:23:38.180 --> 00:23:39.639 labeled Custom 385 00:23:39.639 --> 00:23:42.520 to actually specify the size we want 386 00:23:42.520 --> 00:23:45.559 The canvas is currently too small, right? 387 00:23:45.559 --> 00:23:46.880 If it's 100x100, it's too small 388 00:23:46.880 --> 00:23:55.039 So, horizontally, if we set it to about 500 389 00:23:55.039 --> 00:23:57.240 vertically to 600, it should fit here 390 00:23:57.240 --> 00:24:01.872 Set it to about 600 in height as well 391 00:24:06.119 --> 00:24:08.559 600 should be sufficient 392 00:24:08.559 --> 00:24:11.479 Let's create it in a square shape with dimensions of 600x600 393 00:24:11.479 --> 00:24:13.639 I'll just bring the position down a bit 394 00:24:13.639 --> 00:24:16.880 Let's start by adjusting the Button Move position 395 00:24:16.880 --> 00:24:20.200 I'll move Position X and 396 00:24:20.200 --> 00:24:24.679 Position Y down by about 200 397 00:24:24.679 --> 00:24:27.920 I'll just bring it down by 150 instead, since 200 seems a bit too much 398 00:24:27.920 --> 00:24:33.079 Next, I'll set the Y value of Normal Move to 0 399 00:24:33.079 --> 00:24:39.399 Select Move Type will be around -200 400 00:24:39.399 --> 00:24:44.060 With these settings, it should arrange the layout in this kind of arrangement 401 00:24:47.079 --> 00:24:50.440 So, let's compile and save it once 402 00:24:50.440 --> 00:24:54.040 Let's go back to HunetVRPlayer 403 00:24:54.040 --> 00:24:57.559 and this time, we'll adjust the Draw Size of MainWidget 404 00:24:57.559 --> 00:25:01.320 to match the earlier Canvas Size of 405 00:25:01.320 --> 00:25:02.380 600x600 406 00:25:05.399 --> 00:25:09.200 Currently, the screen is being viewed 407 00:25:09.200 --> 00:25:10.519 from the camera's perspective 408 00:25:10.519 --> 00:25:13.640 so it would end up showing the back of the widget 409 00:25:13.640 --> 00:25:18.480 So, if we move the widget a bit forward 410 00:25:18.480 --> 00:25:20.867 and rotate it 180 degrees 411 00:25:20.867 --> 00:25:23.760 it should appear as if it's right in front of our eyes 412 00:25:23.760 --> 00:25:27.640 when viewed from the camera's perspective 413 00:25:27.640 --> 00:25:31.000 So, for the location adjustment 414 00:25:31.000 --> 00:25:34.720 let's position it about 4 meters forward 415 00:25:34.720 --> 00:25:39.760 and rotate it 180 degrees on the Z-axis 416 00:25:39.760 --> 00:25:44.119 to ensure it appears correctly when outputted like this 417 00:25:44.119 --> 00:25:50.079 Let's compile and save to see how it looks 418 00:25:50.079 --> 00:25:53.799 It seems a bit too large 419 00:25:53.799 --> 00:25:58.119 and also a bit sunken down 420 00:25:58.119 --> 00:26:00.679 When converting pixel sizes to world sizes 421 00:26:00.679 --> 00:26:03.640 sometimes the size can become too large like this 422 00:26:03.640 --> 00:26:07.200 So, we should either reduce the overall size a bit 423 00:26:07.200 --> 00:26:09.399 or lift it up slightly 424 00:26:09.399 --> 00:26:11.440 either one should help 425 00:26:11.440 --> 00:26:13.279 Let's try lifting it up first 426 00:26:13.279 --> 00:26:15.600 We'll lift it up a bit first 427 00:26:15.600 --> 00:26:17.379 and then 428 00:26:20.200 --> 00:26:21.350 compile and save 429 00:26:23.231 --> 00:26:24.906 And now, when you look again 430 00:26:27.480 --> 00:26:29.399 the widget should appear 431 00:26:29.399 --> 00:26:32.760 more like an actor 432 00:26:32.760 --> 00:26:35.600 in the world, right? 433 00:26:35.600 --> 00:26:37.959 But since there's 434 00:26:37.959 --> 00:26:39.880 no mouse cursor in VR 435 00:26:39.880 --> 00:26:42.320 you might be unsure how to press the button 436 00:26:42.320 --> 00:26:46.003 If you're using controllers, you might be unsure how to press the button 437 00:26:46.003 --> 00:26:48.119 I'll help you implement the button's functionality 438 00:26:48.119 --> 00:26:50.679 and figure out 439 00:26:50.679 --> 00:26:52.001 how to press it 440 00:26:53.034 --> 00:26:57.588 Widget Interaction 441 00:26:59.079 --> 00:27:01.916 First, let's implement the functionality of the button 442 00:27:04.440 --> 00:27:07.959 Select the Normal Move button 443 00:27:07.959 --> 00:27:12.839 then click on the "+" button 444 00:27:12.839 --> 00:27:15.160 next to On Clicked to add an event 445 00:27:15.160 --> 00:27:18.640 Then, it will switch to the Graph panel, and you'll see a new event created 446 00:27:18.640 --> 00:27:24.710 Here, you'll first check if the player has been properly retrieved 447 00:27:24.710 --> 00:27:26.089 Is Valid 448 00:27:31.514 --> 00:27:33.559 First, check if the player exists 449 00:27:33.559 --> 00:27:37.441 If they do 450 00:27:39.986 --> 00:27:46.625 set the Use Teleport value 451 00:27:46.625 --> 00:27:49.000 on this player 452 00:27:49.000 --> 00:27:53.559 If it's Valid and it's Normal Move 453 00:27:53.559 --> 00:27:54.839 then it should be False, correct? 454 00:27:54.839 --> 00:27:57.679 So, you'll set it to False in the False state 455 00:27:57.679 --> 00:27:59.720 Next, go back to the Designer panel 456 00:27:59.720 --> 00:28:01.440 select Teleport Move 457 00:28:01.440 --> 00:28:03.480 and then click the "+" button 458 00:28:03.480 --> 00:28:07.959 next to On Clicked 459 00:28:07.959 --> 00:28:09.720 Since it's the same 460 00:28:09.720 --> 00:28:11.839 I'll duplicate the one above with Ctrl+D 461 00:28:11.839 --> 00:28:14.880 After duplicating 462 00:28:14.880 --> 00:28:18.760 connect it to Is Valid 463 00:28:18.760 --> 00:28:21.599 and in this case, Use Teleport should be True 464 00:28:25.466 --> 00:28:29.359 So, when clicking the Normal button 465 00:28:29.359 --> 00:28:32.001 Teleport should be set to False 466 00:28:32.001 --> 00:28:33.440 The name is set wrong 467 00:28:33.440 --> 00:28:34.640 I'll go ahead and change the name as needed 468 00:28:34.640 --> 00:28:37.039 I'll rename it to Button_TeleportMove 469 00:28:37.039 --> 00:28:40.799 instead of 470 00:28:40.799 --> 00:28:45.400 Normal Move_1 471 00:28:45.400 --> 00:28:47.159 I'll change the name of the button 472 00:28:47.159 --> 00:28:49.960 It looks like we didn't change the button name 473 00:28:49.960 --> 00:28:51.919 After that, when you come back to the graph 474 00:28:51.919 --> 00:28:53.880 you'll see that the name has been updated 475 00:28:53.880 --> 00:28:55.880 In the Designer panel 476 00:28:55.880 --> 00:28:59.880 click the "+" button 477 00:28:59.880 --> 00:29:04.000 next to On Clicked for the updated Teleport Move variable 478 00:29:04.000 --> 00:29:09.640 and then connect this event to Valid like this 479 00:29:09.640 --> 00:29:12.400 So, pressing the Teleport Move button will set 480 00:29:12.400 --> 00:29:14.520 Use Teleport to True 481 00:29:14.520 --> 00:29:16.239 and pressing the Normal Move button will set 482 00:29:16.239 --> 00:29:17.919 Teleport to False 483 00:29:17.919 --> 00:29:20.679 and the functionality has been implemented correctly 484 00:29:20.679 --> 00:29:22.520 Then, we can test it out by 485 00:29:22.520 --> 00:29:26.080 simply clicking to see if everything works as intended 486 00:29:26.080 --> 00:29:32.000 We'll use the right hand's Index Trigger 487 00:29:32.000 --> 00:29:33.679 to simulate a click and test it out 488 00:29:33.679 --> 00:29:35.919 And we'll implement it to click like a remote control 489 00:29:35.919 --> 00:29:39.080 Let's give it a try 490 00:29:39.080 --> 00:29:39.980 First 491 00:29:44.227 --> 00:29:49.730 right-click in the Inputs section 492 00:29:49.730 --> 00:29:51.230 and add 493 00:29:51.230 --> 00:29:52.640 a new Input Action 494 00:29:52.640 --> 00:30:02.080 I will create a button 495 00:30:02.080 --> 00:30:04.679 named 496 00:30:04.679 --> 00:30:07.039 IndexTrigger_Right 497 00:30:07.039 --> 00:30:09.939 The value type for this 498 00:30:09.939 --> 00:30:11.440 should be set to True/False 499 00:30:11.440 --> 00:30:12.579 Pressed/Not Pressed 500 00:30:18.440 --> 00:30:20.590 Then 501 00:30:20.590 --> 00:30:21.799 open the Mapping Context 502 00:30:21.799 --> 00:30:24.719 We need to add one more item to the Mapping Context 503 00:30:24.719 --> 00:30:28.479 Add another mapping 504 00:30:28.479 --> 00:30:35.400 and select 505 00:30:35.400 --> 00:30:39.080 IA_IndexTrigger_Right Right for it 506 00:30:39.080 --> 00:30:43.799 For the key 507 00:30:43.799 --> 00:30:44.843 instead of Oculus Touch (R) Trigger Axis 508 00:30:44.843 --> 00:30:46.520 assign the 509 00:30:46.520 --> 00:30:47.425 Trigger True/False button 510 00:30:50.422 --> 00:30:52.138 Save it again 511 00:30:56.741 --> 00:31:00.440 Go back to the HunetVRPlayer pawn 512 00:31:00.440 --> 00:31:03.146 and in the Event Graph 513 00:31:03.146 --> 00:31:05.479 add another Event button Event 514 00:31:05.479 --> 00:31:08.520 Right-click at the very bottom 515 00:31:08.520 --> 00:31:15.119 and select IA_IndexTrigger_Right 516 00:31:15.119 --> 00:31:16.719 IndexTrigger_Right 517 00:31:16.719 --> 00:31:18.348 by right-clicking them 518 00:31:22.100 --> 00:31:26.876 So here, when it starts 519 00:31:26.876 --> 00:31:29.201 give it a click effect, and when it completes 520 00:31:29.201 --> 00:31:32.751 give it a click to release effect, right? 521 00:31:32.751 --> 00:31:36.039 So, we have a way to give a click effect 522 00:31:36.039 --> 00:31:38.620 remotely like a remote control 523 00:31:38.620 --> 00:31:42.200 Here in Components 524 00:31:42.200 --> 00:31:44.679 if you search for "Widget" 525 00:31:44.679 --> 00:31:46.440 you'll find 526 00:31:46.440 --> 00:31:47.190 a component 527 00:31:47.190 --> 00:31:48.520 related to Widget 528 00:31:48.520 --> 00:31:50.359 and Interaction 529 00:31:50.359 --> 00:31:53.679 Add this component 530 00:31:53.679 --> 00:32:05.840 I'll name it 531 00:32:05.840 --> 00:32:06.640 RightWidgetInteractionComp 532 00:32:06.640 --> 00:32:10.571 Even though the name is long 533 00:32:10.571 --> 00:32:13.440 I'll attach RightWidgetInteractionComp 534 00:32:13.440 --> 00:32:16.359 as a child component 535 00:32:16.359 --> 00:32:19.758 of the Right Hand Motion Controller 536 00:32:19.758 --> 00:32:27.231 under the Motion Controller category 537 00:32:27.231 --> 00:32:30.302 Then, if you look at the Viewport 538 00:32:36.291 --> 00:32:40.498 currently there's no indication on the right hand 539 00:32:40.498 --> 00:32:44.919 but if you check "Show Debug" in the Details panel of WidgetInteractionComp 540 00:32:44.919 --> 00:32:47.280 a red line will suddenly appear 541 00:32:47.280 --> 00:32:54.479 on the right hand 542 00:32:54.479 --> 00:32:57.479 It seems you can't see it here right now 543 00:32:57.479 --> 00:33:00.400 but let's compile and save first 544 00:33:00.400 --> 00:33:01.691 Then, we can check it outside 545 00:33:10.651 --> 00:33:11.501 Then 546 00:33:17.368 --> 00:33:19.581 why is the right hand's motion controller 547 00:33:19.581 --> 00:33:21.600 so far apart from the hand? 548 00:33:21.600 --> 00:33:23.960 Why is the hand so far apart like this? 549 00:33:23.960 --> 00:33:26.601 You might see it drawn like this in the upper direction 550 00:33:38.751 --> 00:33:42.440 Right now, the position of RightWidgetInteractionComp 551 00:33:42.440 --> 00:33:44.520 is probably not at 0, 0, 0 552 00:33:44.520 --> 00:33:46.624 So, I'll adjust it to 0, 0, 0 like this 553 00:33:48.960 --> 00:33:52.063 It should now match the position of the Motion Controller 554 00:33:55.241 --> 00:33:59.080 So, placing it like this means 555 00:33:59.080 --> 00:34:01.200 the hand's orientation doesn't quite match right now 556 00:34:01.200 --> 00:34:04.320 So, I'll try moving it as a child of the hand 557 00:34:04.320 --> 00:34:07.719 I'll move WidgetInteractionComp 558 00:34:07.719 --> 00:34:11.320 as a child of the hand 559 00:34:11.320 --> 00:34:13.987 and set all rotations to 0, 0, 0 to make sure there's no rotation 560 00:34:17.581 --> 00:34:20.039 If you place it at 0, 0, 0 for now 561 00:34:20.039 --> 00:34:23.159 WidgetInteractionComp will be facing upwards 562 00:34:23.159 --> 00:34:25.719 with the red line 563 00:34:25.719 --> 00:34:28.840 So, since it shouldn't be facing upwards 564 00:34:28.840 --> 00:34:32.000 I'll bring it down a bit like this 565 00:34:32.000 --> 00:34:36.440 The red line will point like this now, right? 566 00:34:36.440 --> 00:34:43.320 I'll rotate it like this 567 00:34:43.320 --> 00:34:46.159 so that WidgetInteractionComp's direction 568 00:34:46.159 --> 00:34:48.280 matches the hand's direction 569 00:34:48.280 --> 00:34:50.960 Since firing from the wrist seems odd 570 00:34:50.960 --> 00:34:53.719 I'll move it forward to draw it 571 00:34:53.719 --> 00:34:56.520 around the middle of the hand 572 00:34:56.520 --> 00:35:03.039 near the middle finger 573 00:35:03.039 --> 00:35:06.239 When you press Play 574 00:35:06.239 --> 00:35:08.599 now it displays correctly aligned with the right hand 575 00:35:08.599 --> 00:35:10.400 and when you get close to the button 576 00:35:10.400 --> 00:35:12.919 there's an effect indicating you've touched the button 577 00:35:12.919 --> 00:35:15.280 When you touch it 578 00:35:15.280 --> 00:35:17.319 what we need to do 579 00:35:23.071 --> 00:35:26.608 next is 580 00:35:26.608 --> 00:35:29.960 set it up 581 00:35:29.960 --> 00:35:32.679 so that the click effect in WidgetInteractionComp 582 00:35:32.679 --> 00:35:34.760 triggers when you press the button 583 00:35:34.760 --> 00:35:39.719 So 584 00:35:39.719 --> 00:35:41.440 when we press 585 00:35:41.440 --> 00:35:43.080 the IndexTrigger_Right button 586 00:35:43.080 --> 00:35:46.632 during the Started event 587 00:35:46.632 --> 00:35:49.280 we'll use 588 00:35:49.280 --> 00:35:52.559 Press Pointer Key 589 00:35:52.559 --> 00:35:53.719 in WidgetInteractionComp 590 00:35:53.719 --> 00:35:55.440 to trigger 591 00:35:55.440 --> 00:35:57.159 the click effect 592 00:35:57.159 --> 00:35:59.159 So, during Press Started 593 00:35:59.159 --> 00:36:00.239 we'll add the press effect 594 00:36:00.239 --> 00:36:03.479 when the button is pressed 595 00:36:03.479 --> 00:36:06.119 During this 596 00:36:06.119 --> 00:36:09.159 the key effect will apply to the left mouse button 597 00:36:09.159 --> 00:36:10.239 When we usually click a button 598 00:36:10.239 --> 00:36:12.880 we typically use the Left Mouse Button 599 00:36:12.880 --> 00:36:14.479 You can either find it directly here 600 00:36:14.479 --> 00:36:17.039 or like before 601 00:36:17.039 --> 00:36:19.283 once you select it here 602 00:36:19.283 --> 00:36:22.359 click again with the mouse, and it will automatically change to Left Mouse Button 603 00:36:22.359 --> 00:36:26.055 When releasing 604 00:36:26.055 --> 00:36:27.207 we should also check that the button has been released 605 00:36:27.207 --> 00:36:29.960 So, during Completed 606 00:36:29.960 --> 00:36:35.700 we'll add the effect of releasing the pointer key 607 00:36:35.700 --> 00:36:39.000 to indicate that the button has been released 608 00:36:39.000 --> 00:36:41.960 So, I'll assign 609 00:36:41.960 --> 00:36:46.280 Left Mouse Button here 610 00:36:46.280 --> 00:36:48.520 and this function will be structured 611 00:36:48.520 --> 00:36:49.559 to execute 612 00:36:49.559 --> 00:36:52.119 when Completed 613 00:36:52.119 --> 00:36:55.880 Alright, so the last thing we need to do is 614 00:36:55.880 --> 00:36:58.119 to associate the Widget 615 00:36:58.119 --> 00:37:01.400 with the Hunet Player pawn 616 00:37:01.400 --> 00:37:04.280 that we created earlier 617 00:37:04.280 --> 00:37:07.439 You've already created the variable for the player 618 00:37:07.439 --> 00:37:10.119 We'll pass that variable here 619 00:37:10.119 --> 00:37:15.280 First, we'll get 620 00:37:15.280 --> 00:37:25.000 the Widget in MainWidget 621 00:37:25.000 --> 00:37:30.410 then cast 622 00:37:30.410 --> 00:37:31.730 this Widget to WBP_MainWidget 623 00:37:36.660 --> 00:37:38.560 Then 624 00:37:38.560 --> 00:37:42.640 in the Set Player variable here 625 00:37:42.640 --> 00:37:46.000 we'll pass the Self value 626 00:37:46.000 --> 00:37:53.839 to the Player variable 627 00:37:53.839 --> 00:37:59.000 So, we need to pass the Player 628 00:37:59.000 --> 00:38:01.800 to the Widget 629 00:38:01.800 --> 00:38:03.400 so that MainWidget can receive the value 630 00:38:03.400 --> 00:38:04.800 from the Player variable 631 00:38:04.800 --> 00:38:09.079 and decide whether to teleport or change the value 632 00:38:09.079 --> 00:38:11.560 So, let's go back 633 00:38:11.560 --> 00:38:13.450 and try playing it again 634 00:38:16.380 --> 00:38:18.239 Then 635 00:38:18.239 --> 00:38:21.160 now we can point and interact with the button like this 636 00:38:21.160 --> 00:38:22.640 So, for example 637 00:38:22.640 --> 00:38:24.680 if I'm currently set to teleport 638 00:38:24.680 --> 00:38:27.119 clicking Normal would allow me 639 00:38:27.119 --> 00:38:29.520 to move forward and backward like this 640 00:38:29.520 --> 00:38:32.040 If you select Normal, it switches to normal movement mode 641 00:38:32.040 --> 00:38:34.180 and if you press Teleport 642 00:38:34.180 --> 00:38:37.359 it switches to teleport mode, right? 643 00:38:37.359 --> 00:38:39.239 If you press Normal again, it returns to this mode 644 00:38:39.239 --> 00:38:43.479 If you press Teleport, it switches back to this mode 645 00:38:43.479 --> 00:38:45.751 You can confirm that it's working well 646 00:38:53.711 --> 00:38:56.946 In VR 647 00:38:56.946 --> 00:38:59.599 using World Space UI allows us to effectively utilize widgets 648 00:38:59.599 --> 00:39:02.711 enabling interaction with the environment through UI elements 649 00:39:02.711 --> 00:39:08.360 In this world-space widget setup 650 00:39:08.360 --> 00:39:10.720 unlike screen-space widgets 651 00:39:10.720 --> 00:39:12.551 that can only be drawn on a plane 652 00:39:12.551 --> 00:39:16.161 the monitor shape is 653 00:39:16.161 --> 00:39:18.610 flat 654 00:39:18.610 --> 00:39:22.839 But this HunetVRPlayer 655 00:39:22.839 --> 00:39:25.840 has come to the MainWidget Componen 656 00:39:25.840 --> 00:39:28.245 In world-space mode 657 00:39:31.321 --> 00:39:32.674 there's a geometry mode 658 00:39:35.980 --> 00:39:38.000 below 659 00:39:38.000 --> 00:39:42.040 If it's labeled as Plane 660 00:39:42.040 --> 00:39:44.341 it means it draws on a flat surface like the traditional screen 661 00:39:44.341 --> 00:39:49.279 If you change this to Cylinder 662 00:39:49.279 --> 00:39:52.211 let me take a look at it in the Viewport 663 00:39:52.211 --> 00:39:53.911 How does it look now? 664 00:39:53.911 --> 00:39:57.319 It looks slightly curved, doesn't it? 665 00:39:57.319 --> 00:39:58.520 Here in Cylinder 666 00:39:58.520 --> 00:40:00.444 there's something called Cylinder Arc Angle 667 00:40:00.444 --> 00:40:02.494 If you decrease the Cylinder Arc Angle 668 00:40:02.494 --> 00:40:05.144 to 1, it becomes completely flat 669 00:40:05.144 --> 00:40:09.814 and if you set it to 180, it becomes fully curved 670 00:40:09.814 --> 00:40:12.464 For example, what we've created is 671 00:40:12.464 --> 00:40:14.814 long vertically, so it doesn't matter 672 00:40:14.814 --> 00:40:17.014 but if it's too long horizontally 673 00:40:17.014 --> 00:40:20.000 we might exceed the field of view when interacting with buttons 674 00:40:20.000 --> 00:40:22.202 In VR, it's common to adjust widgets like this 675 00:40:22.202 --> 00:40:26.452 slightly curved 676 00:40:26.452 --> 00:40:28.639 to fit the field of view better 677 00:40:28.639 --> 00:40:33.139 to avoid issues where text 678 00:40:33.139 --> 00:40:37.279 or button images aren't clearly visible 679 00:40:37.279 --> 00:40:40.279 Yes, in other VR UI designs 680 00:40:40.279 --> 00:40:43.605 you may see panels stretched horizontally and curved 681 00:40:43.605 --> 00:40:46.400 to better fit the user's field of view and make interactions more accessible 682 00:40:46.400 --> 00:40:48.233 We can use these features 683 00:40:48.233 --> 00:40:51.933 to easily curve widgets 684 00:40:51.933 --> 00:40:54.560 and display them on the screen for better visibility and usability in VR 685 00:40:54.560 --> 00:40:55.910 So, how does this look? 686 00:40:55.910 --> 00:41:00.200 It looks slightly more curved, giving it a sense of depth 687 00:41:00.200 --> 00:41:02.450 688 00:41:02.450 --> 00:41:04.200 it remains visible 689 00:41:04.200 --> 00:41:07.550 from my perspective 690 00:41:07.550 --> 00:41:11.599 even if I turn my head a bit 691 00:41:11.599 --> 00:41:15.080 Of course, this is only possible when placed in the world space 692 00:41:15.080 --> 00:41:18.530 Then, one more thing to note is that 693 00:41:18.530 --> 00:41:20.880 the size of the widget is 694 00:41:20.880 --> 00:41:22.480 likely in pixels 695 00:41:22.480 --> 00:41:24.418 The values here, like 600 696 00:41:24.418 --> 00:41:27.918 in position and size 697 00:41:27.918 --> 00:41:31.470 are in screen coordinates, which means they are in pixel units 698 00:41:31.470 --> 00:41:36.020 If you draw this in world space like MainWidget earlier 699 00:41:36.020 --> 00:41:38.870 those coordinates will be converted to centimeters 700 00:41:38.870 --> 00:41:41.680 in the world space 701 00:41:41.680 --> 00:41:44.330 So, 600cm x 600cm would translate to a panel 702 00:41:44.330 --> 00:41:47.201 that's 6m x 6m in size 703 00:41:47.201 --> 00:41:49.701 It's quite big, right? So, as you saw earlier 704 00:41:49.701 --> 00:41:52.500 the widget looks really grand, doesn't it? 705 00:41:52.500 --> 00:41:57.700 So when displaying the UI in a world method like this 706 00:41:57.700 --> 00:41:59.500 the coordinate system changes to centimeters 707 00:41:59.500 --> 00:42:02.301 instead of pixels because it's in centimeters 708 00:42:02.301 --> 00:42:04.901 I think it would be good to keep in mind that 709 00:42:04.901 --> 00:42:09.279 it needs to be scaled down a bit more 710 00:42:09.279 --> 00:42:13.091 Then, let's wrap it up here for today 711 00:42:13.091 --> 00:42:16.821 Thank you for your effort 712 00:42:16.821 --> 00:42:19.039 in listening to the long lecture 713 00:42:19.039 --> 00:42:22.520 Let's summarize what we learned in this session 714 00:42:22.520 --> 00:42:26.620 First, due to the particular characteristics of the fisheye lens in VR 715 00:42:26.620 --> 00:42:29.721 it is important to note that 716 00:42:29.721 --> 00:42:31.671 traditional screen-based overlays are not possible 717 00:42:31.671 --> 00:42:34.451 and thus the UI must be converted to a world-based method 718 00:42:34.451 --> 00:42:38.451 Second, in VR, the user's gaze is free 719 00:42:38.451 --> 00:42:41.479 providing a much wider field of view compared to a monitor 720 00:42:41.479 --> 00:42:44.529 Because of this, as the lateral limits extend 721 00:42:44.529 --> 00:42:46.829 the contents of the UI at the edges 722 00:42:46.829 --> 00:42:49.639 may not be easily visible 723 00:42:49.639 --> 00:42:52.039 so a curved method of bending the widget 724 00:42:52.039 --> 00:42:54.320 into a curved shape is used 725 00:42:54.320 --> 00:42:56.920 Third, by using the Press Pointer Key node provided by Unreal Engine 726 00:42:56.920 --> 00:42:59.800 you can ensure that 727 00:42:59.800 --> 00:43:02.400 the click effect of keyboard or mouse keys 728 00:43:02.400 --> 00:43:05.200 is applied identically 729 00:43:05.200 --> 00:43:07.520 when pressing buttons on VR controllers 730 00:43:09.811 --> 00:43:10.511 Creating Widgets: Using World-Based UI in VR In VR, traditional screen-based overlays are not possible due to the unique nature of VR lenses. Therefore, it is necessary to use world-based UI approaches when creating widgets 731 00:43:10.511 --> 00:43:11.011 Creating a UI Folder in Content Drawer Select [+Add] -> [User Interface] -> [Widget Blueprint] to create a Widget Blueprint 732 00:43:11.011 --> 00:43:12.111 Open the Widget Blueprint Settings and add a Canvas Panel and a Text component While selecting the Text component, choose "Center" for Anchors in the Details panel 733 00:43:12.111 --> 00:43:12.611 Set the Alignment of the Pivot to the center of the component (0.5, 0.5) Set the Position and Size, then enter Text, choose the Font, Size, and Alignment 734 00:43:12.611 --> 00:43:13.111 Add a Button component named "Button_NormalMove" Add a Text component as a child component of the Button_NormalMove component 735 00:43:13.111 --> 00:43:13.649 Add a Button component named "Button_TeleportMove" and add a Text component as a child component of it 736 00:43:13.649 --> 00:43:14.149 Creating World-Type UI Rendering Methods in VR and Fisheye Lenses 737 00:43:14.149 --> 00:43:14.649 Change the Canvas setting at the top of the Widget Designer panel of WBP_MainWidget from [Fill Screen] to [Custom] 738 00:43:14.649 --> 00:43:15.149 Set Width and Height to 600 each 739 00:43:15.149 --> 00:43:15.649 Setting up Widget components Creating a Widget Component by selecting [+Add] -> [Widget] in the Components panel 740 00:43:15.649 --> 00:43:16.149 In the Details panel, set the Space item to World and assign the WBP_MainWidget file created earlier to the Widget Class item 741 00:43:16.149 --> 00:43:16.649 Declare a boolean variable named "Use Teleport" 742 00:43:16.649 --> 00:43:17.149 Connect the Triggered execution pin of the node: if the value of "Use Teleport" is True, execute the [Draw Teleport] node; if False, execute the [Normal Move] node 743 00:43:17.149 --> 00:43:17.688 Connect the Completed execution pin of the node: if the value of "Use Teleport" is True, execute the [Teleport Action] node; if False, execute the [Normal Move] node 744 00:43:17.688 --> 00:43:18.262 Implementing Widget Interaction Adding Widget Interaction Component 745 00:43:18.262 --> 00:43:18.796 Add a WidgetInteraction component as a child component of the RightHand component by selecting [+Add] -> [WidgetInteraction], and then set its name 746 00:43:18.796 --> 00:43:19.330 While selecting the Widget Interaction component, check (set to True) the Show Debug option in the right-side Details panel 747 00:43:19.330 --> 00:43:19.880 Set the Rotation values to (-90, 0, 90) so that the debug lines align with the direction of the hand 748 00:43:19.880 --> 00:43:20.475 Create a new Input Action file and set the Value Type to Digital (bool) 749 00:43:20.475 --> 00:43:21.059 Double-click on the file to open the settings window, then add IA_IndexTrigger_Right key to the Mappings array 750 00:43:21.059 --> 00:43:21.540 Setting up Curved UI Adjusting widget shapes in a curved manner to solve the issue of outer UI content not being clearly visible due to wide field of view 751 00:43:21.540 --> 00:43:22.137 Change the Geometry Mode to [Cylinder] in the Details panel of the MainWidget component 752 00:43:22.137 --> 00:43:23.137 The End