Extend the default teleport to multi user teleport¶
This script implements group teleport functionality. It uses the default teleport interaction and implements an additional group teleport interaction. How to combine default and custom interactions can be seen in the “Combine a custom and a default device interaction” example.
When GroupTeleport is initialized, two virtual buttons are defined on the touchpad of a VR controller. The upper half is one button and the lower half another. How virtual buttons work is shown in the “Define and use virtual buttons on the touchpad of a VR controller” example.
The actions of the default teleport are now mapped to the lower virtual button. Further information about remapping the default interactions can also be found in the “Combine a custom and a default device interaction” example.
A new interaction is created for the group teleport. This handles the switching between the regular and the group teleport, by using the upper button. If group teleport is active, all participants in the session will also be teleported to near the target position.
After all signals are connected to their corresponding methods, the geometry positioning is set up by using a parent constraint.
82self.leftConstraint = vrConstraintService.createParentConstraint([self.leftController.getNode()], self.leftDisk, True)
83self.rightConstraint = vrConstraintService.createParentConstraint([self.rightController.getNode()], self.rightDisk, True)
This geometry is positioned on top of the touchpad of the controller. It visualizes the current state. The upper button will show “Single” if the regular teleport is active and “Group” if group teleport is active. The buttons will be highlighted, when the user presses them. The setting of which geometry is visible is handled in the corresponding methods. The actual group teleport is done by syncing the camera node with all other users.
129cameraNode = vrCameraService.getActiveCamera()
130vrSessionService.syncNode(cameraNode)
For further information about syncing nodes refer to the “Synchronization during a collaboration session” example.
1# © 2024 Autodesk, Inc. All rights reserved.
2
3# Class for the group teleport
4class GroupTeleport:
5 def __init__(self):
6 self.isActive = False
7 self.setupButtons()
8 self.setupInteraction()
9 self.setupVisualization()
10
11 def setupButtons(self):
12 # Create touchpad layout. Upper half of pad is one button ...
13 self.padUp = vrdVirtualTouchpadButton("padup", 0.0, 1.0, 270.0, 90.0)
14 # ... and the lower half is another button
15 self.padDown = vrdVirtualTouchpadButton("paddown", 0.0, 1.0, 90.0, 270.0)
16
17 # Get the controllers
18 self.leftController = vrDeviceService.getVRDevice("left-controller")
19 self.rightController = vrDeviceService.getVRDevice("right-controller")
20
21 # Assign the virtual touchpad buttons to the left ...
22 self.leftController.addVirtualButton(self.padUp, "Touchpad")
23 self.leftController.addVirtualButton(self.padDown, "Touchpad")
24 # ... and to the right controller
25 self.rightController.addVirtualButton(self.padUp, "Touchpad")
26 self.rightController.addVirtualButton(self.padDown, "Touchpad")
27
28 # Map the default teleport interaction top the lower button
29 self.teleportInteraction = vrDeviceService.getInteraction("Teleport")
30 self.teleportInteraction.setControllerActionMapping("prepare", "any-paddown-touched")
31 self.teleportInteraction.setControllerActionMapping("execute", "any-paddown-pressed")
32 self.teleportInteraction.setControllerActionMapping("abort", "any-paddown-untouched")
33
34 def setupInteraction(self):
35 # Create an interaction for the group teleport
36 self.groupTeleportInteraction = vrDeviceService.createInteraction("GroupTeleport")
37
38 # Map the toggle active to the upper pad button
39 self.beginToggleAction = self.groupTeleportInteraction.createControllerAction("any-padup-pressed")
40 self.toggleActiveAction = self.groupTeleportInteraction.createControllerAction("any-padup-released")
41 # Get the execute action of the teleport
42 self.teleportExecuteAction = self.teleportInteraction.getControllerAction("execute")
43 # Map the pad down for some visual indicators
44 self.teleportExecuteFinishedAction = self.groupTeleportInteraction.createControllerAction("any-paddown-released")
45
46 # Connect the signals
47 self.beginToggleAction.signal().triggered.connect(self.beginToggle)
48 self.toggleActiveAction.signal().triggered.connect(self.toggleActive)
49 self.teleportExecuteAction.signal().triggered.connect(self.execute)
50 self.teleportExecuteFinishedAction.signal().triggered.connect(self.executeFinished)
51
52 def setupVisualization(self):
53 # Load geometry for controller touchpads
54 loadGeometry("$VRED_EXAMPLES/vr/GroupTeleportPad.osb")
55 # Find the touchpad geometry in the scene that shows the virtual buttons
56 oldLeftDisk = findNode("ControllerDisk")
57
58 # Create a lookup for the different visualization states
59 self.diskVisualizations = dict()
60
61 # Check if the touchpad geometry has been found
62 if oldLeftDisk.isValid():
63 # Geometry is also needed for the right controller, therefore clone it
64 oldRightDisk = cloneNode(oldLeftDisk, False)
65 # Convert to new vrdNode
66 self.leftDisk = vrNodeService.getNodeFromId(oldLeftDisk.getID())
67 self.rightDisk = vrNodeService.getNodeFromId(oldRightDisk.getID())
68
69 # Setup all touchpad geometries for the left hand
70 self.diskVisualizations["leftSingle"] = self.leftDisk.getChild(0)
71 self.diskVisualizations["leftGroup"] = self.leftDisk.getChild(1)
72 self.diskVisualizations["leftUp"] = self.leftDisk.getChild(2)
73 self.diskVisualizations["leftSingleDown"] = self.leftDisk.getChild(3)
74 self.diskVisualizations["leftGroupDown"] = self.leftDisk.getChild(4)
75
76 # Setup all touchpad geometries for the right hand
77 self.diskVisualizations["rightSingle"] = self.rightDisk.getChild(0)
78 self.diskVisualizations["rightGroup"] = self.rightDisk.getChild(1)
79 self.diskVisualizations["rightUp"] = self.rightDisk.getChild(2)
80 self.diskVisualizations["rightSingleDown"] = self.rightDisk.getChild(3)
81 self.diskVisualizations["rightGroupDown"] = self.rightDisk.getChild(4)
82
83 # Use a constraint to position the touchpad geometry correctly
84 self.leftConstraint = vrConstraintService.createParentConstraint([self.leftController.getNode()], self.leftDisk, True)
85 self.rightConstraint = vrConstraintService.createParentConstraint([self.rightController.getNode()], self.rightDisk, True)
86
87 self.initialized = True
88 else:
89 self.initialized = False
90
91 # Set the visualization of the devices to controller instead of hands
92 self.leftController.setVisualizationMode(0)
93 self.rightController.setVisualizationMode(0)
94
95 # Set the visualization state of the touchpad disk
96 self.showSingleDisk()
97
98 def toggleActive(self, action, device):
99 self.isActive = not self.isActive
100 if self.isActive:
101 # Show the touchpad geometry used for group teleport
102 self.showGroupDisk()
103 else:
104 # Show the touchpad geometry used for regular teleport
105 self.showSingleDisk()
106
107
108 def beginToggle(self, action, device):
109 left = True
110 # Check if the right or the left controller triggered this
111 if 'right' in device.getName():
112 left = False
113 # Highlights the upper button
114 self.showDiskUp(left)
115
116
117 def execute(self, action, device):
118 left = True
119 # Check if the right or the left controller triggered this
120 if 'right' in device.getName():
121 left = False
122
123 # Highlight the lower button
124 self.showDiskDown(left)
125
126 # If inactive just return as the regular teleport will work as usual
127 if not self.isActive:
128 return
129
130 # Sync the active camera with all participants in the session to teleport them, too.
131 cameraNode = vrCameraService.getActiveCamera()
132 vrSessionService.syncNode(cameraNode)
133
134
135 def executeFinished(self, action, device):
136 if self.isActive:
137 # Show 'Group' on the upper button
138 self.showGroupDisk()
139 else:
140 # Show 'Single' on the upper button
141 self.showSingleDisk()
142
143
144 def hideAllDisks(self):
145 if not self.initialized:
146 return
147
148 # Iterate over the lookup to set all geometries to invisible
149 for name, disk in self.diskVisualizations.items():
150 disk.setVisibilityFlag(False)
151
152
153 def hideDisksOneSided(self, left):
154 if not self.initialized:
155 return
156
157 side = 'right'
158 if left:
159 side = 'left'
160
161 # Iterate over the lookup to set all geometries of one side to invisible
162 for name, disk in self.diskVisualizations.items():
163 if side in name:
164 disk.setVisibilityFlag(False)
165
166
167 def showGroupDisk(self):
168 if not self.initialized:
169 return
170
171 # Hide all touchpad geometries first to ensure only the correct ones will be shown.
172 self.hideAllDisks()
173 # Show the touchpad geometry with 'Group' on the upper button.
174 # Do this for both sides as this state is for both hands
175 self.diskVisualizations["leftGroup"].setVisibilityFlag(True)
176 self.diskVisualizations["rightGroup"].setVisibilityFlag(True)
177
178
179 def showSingleDisk(self):
180 if not self.initialized:
181 return
182
183 # Hide all touchpad geometries first to ensure only the correct ones will be shown.
184 self.hideAllDisks()
185 # Show the touchpad geometry with 'Single' on the upper button.
186 # Do this for both sides as this state is for both hands
187 self.diskVisualizations["leftSingle"].setVisibilityFlag(True)
188 self.diskVisualizations["rightSingle"].setVisibilityFlag(True)
189
190
191 def showDiskUp(self, left):
192 if not self.initialized:
193 return
194
195 # Hide all touchpad geometries for the given side first to ensure only the correct ones will be shown.
196 self.hideDisksOneSided(left)
197
198 # Show the highlighted geometry for the lower button for the given hand.
199 if left:
200 self.diskVisualizations["leftUp"].setVisibilityFlag(True)
201 else:
202 self.diskVisualizations["rightUp"].setVisibilityFlag(True)
203
204
205 def showDiskDown(self, left):
206 if not self.initialized:
207 return
208
209 # Hide all touchpad geometries for the given side first to ensure only the correct ones will be shown.
210 self.hideDisksOneSided(left)
211
212 # Show the highlighted geometry for the upper button for the given hand
213 # It also needs to be distinhuished which mode is currently active to show the correct highlighted geometry.
214 if left:
215 if self.isActive:
216 self.diskVisualizations["leftGroupDown"].setVisibilityFlag(True)
217 else:
218 self.diskVisualizations["leftSingleDown"].setVisibilityFlag(True)
219 else:
220 if self.isActive:
221 self.diskVisualizations["rightGroupDown"].setVisibilityFlag(True)
222 else:
223 self.diskVisualizations["rightSingleDown"].setVisibilityFlag(True)
224
225
226groupTeleport = GroupTeleport()