Showing a flash light in VR
VRFlashlightModule.py
# © 2025 Autodesk, Inc. All rights reserved.
from PySide2 import QtCore,QtWidgets
from vrScenegraph import *
from vrController import *
from vrNodePtr import *
from vrNodeUtils import *
class Flashlight():
def __init__(self):
QtCore.QTimer.singleShot(0, self.init)
def init(self):
self.geo = None
self.on = False
self.createMenu()
pointer = vrDeviceService.getInteraction("Tools Menu")
start = pointer.getControllerAction("showMenu")
start.signal().triggered.connect(self.onMenuOpened)
self.handNode = vrDeviceService.getVRDevice("right-controller").getNode()
self.activeController = vrDeviceService.getVRDevice("right-controller")
def onMenuOpened(self,action,device):
# place the flashlight on the other hand
if device.getName() == "left-controller":
self.handNode = vrDeviceService.getVRDevice("right-controller").getNode()
self.activeController = vrDeviceService.getVRDevice("right-controller")
else:
self.handNode = vrDeviceService.getVRDevice("left-controller").getNode()
self.activeController = vrDeviceService.getVRDevice("left-controller")
def switchOn(self):
if not self.on:
self.getGeo().setActive(True)
self.on = True
# move the flashlight with the hand
self.constraint = vrConstraintService.createParentConstraint([self.handNode],self.geo,False)
self.activeController.signal().moved.connect(self.updateFlashlight)
self.visualizationMode = self.activeController.getVisualizationMode()
self.adjustFlashlight(self.activeController)
def switchOff(self):
if self.on:
self.getGeo().setActive(False)
self.on = False
vrConstraintService.deleteConstraint(self.constraint)
self.activeController.signal().moved.disconnect(self.updateFlashlight)
def createMenu(self):
# png icons as base64 string
onIcon = "iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAAilBMVEX9oRTreSj6twb3qw3ylxjtfibvlBv1pBHxjB/rfSjviiDvix/7vQPxkxvugiPtfiXwix/0nBXuhSL1oRLwjB7rfCf0qQ7ugyP8wQH4swn1pRDwix/ylBn0nBXwiCHtgST1pBHvih/7uwT5tAj4rgv7wAH1oRPvix77ugXuhCP0oBP1oxHwjh3uhCJVyFMlAAAAK3RSTlMAM/////4QJEKBpVHxjTq5FrBj8NjEG+exwjzY7eWF7tbo3eTcTFj8W26hmZCkDQAAAAlwSFlzAAAk6QAAJOkBUCTn+AAAA31JREFUWAntWO12ojAQDUkIVJRGrEpXrVq7220T3v/19uYDRIviYvqvOT1lmjA3dzKTmaGEDB8RxWCMKcUV51xXGPFwOGgeERXjWhvE+wAFEMEQFJMofUj1KIvvAyQkGTuTxSTLxaMc3Q1orVaMiWmRPYhI3w8IRHCkBGBaPP4HoBRH97VE45mZUko8wSty3uMUOZE1yoKqRk4eGtEuJ1ypfImwyZY9gCV9rgF/URrV8kpPatE9YTXgbNhcP8OSUulVM6oWXoy4LrxYP8CxDsOrYSOZqrnkVNUMJ0ovTk8R58g84nWGZMq4UxUp5R5QMDaqmR2fkb96PYApValTSqn2Jmeshj7CEURNBaPhk6smE7JWnk1OtWe4oVUbqZGTm+5yybm0Kg1gxNi5SzxmFN/AUHLvFpicWMUXxtwWHqb1SLb9JpMd21u3INScyYzNWxinYhJjnE59+Stz3oWXlWWYU5Z/eamZiPoBxWtsGUq6tWoJ3TXqHQIQO2bvmUqGALpYv7BtfZ+6l0X5+nrYvL1tnja79f5pv1otV8v9XHa/fcPsb1PWMFA0UNmYMrHLq/hCIPYDij8OzwListqMou8AJAAcz2ZUzTC4fn/fr3FZ4+EMcec7zeie7Xz1bFIs5JchZLu8nCn0/Zn6M0Rho6bZUBr9RlxlfXoX1zMHyOAV4xOX5uP4yuW7COUWxNggumbDtkM2h1aLHrUryyhT53hVvLyi0Lf0t2bIXMNm+ytfFfp0u9efwRAc7U0xRwjEewgSIhubDUUDGMvurW+dNT2lZVi7eXjM+C0Lb7H38setTC6/92mOkSqKfMP14+X3bl4Rk3JUj5fh17i1H0Can9b0cDEtMDLzqxh+6drb47ogEHGAVXW5JrcV+uSpDRwThYEADUOTbsAwhJMJsQxt0xuOIThak8MwRGRjhD3DQy5EtOTBTD64QFgFApxSl2FEHgiwpK55JSIYYP1dEghw2nxPBQIs6UKk03kezORPKlHxuU7DnaF8ZvgcnpNAJoPh1AKGY5jBZMbzHCRDjE86Flm5ysQ2kMnIh4dM4i6HytgANNnGtA1hTLaAps6HZGhLQECGtqbgX2XBTA5bRs0Z+qoXjKGt9MEK/bd5OVjYFP4M0ToM/g49SQFike+QbZAQkyDtIcBFgWTDAnTDDVFRbNYfoeg1qD/Czwl82wn8A1RuSwNXqFYLAAAAAElFTkSuQmCC"
offIcon = "iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAMAAAC5zwKfAAAAe1BMVEWwsbWwsrO1triwsbOur7Gmp6men6GdnqCcnp64ubu1t7ump6mkpKavr7GkpaenqKqmpqm7u72kpaesrK+jpKa0tbeztbeztLWgoaOfoKGoqaurrK+5ury6vL2vsLKnqKqcnZ+trrCbm6CjpKaxsrSmqKi6ur2ioqS5ubt/L2nWAAAAKXRSTlMAI//+/v/+/DFcLkOGZ5KkE6/qHNfsTLP9Ylbq3e7d2sTrM7jMYbN2V7lTpSMAAAAJcEhZcwAAJOkAACTpAVAk5/gAAAMoSURBVFgJ7Zh7c6MgEMBxEVPFJIh4tbVec73n9/+EtzxWc0mrNnAz/aM708AY+LkvdkkZu10yIOE8z4WVYnc7DnfezUBwvFggKz2R86qS9V4cyqKI0pAxbzXn7CilOmaHSJNnq1lT7msm83hg8KNSUgt2FNtNbtVbzpEC0GSDQVGmWNawrVuitAATsa0reuzGrAMuNabN3qxo2IChnV8A7mhuxD1N/VjllIb9soYPAKTLI0AWKK0Q5b9AJrucEnsxbSqAOmyVs4ZNLtQFkFWC28TuVzRkDXTXQM4vLLZLKmGPXr92UvAg7D0RNQwm7wFkeMv5IDsEFmsasgEOEzAExcBwDprmFQLXi8M9gM+cyYeYP0HpCRUmlV73IcPtPiwI9ORmsv0SyOSAXlwrX0+g3cYScp9BHTRXJHpQ6WK3BnwE4UAyjBim10ISkBKJRH9jVKN20cXRraj4dHhe2yH1GvC1XUvPpH/v0pJ3frfgEEtqxrEzX587YzptumdtjNb6pN75knk5VgdqGlhPODU2OuDzwq2zCQiAQM/DkndZbLbiGHPAEWBE6YZvw4AGa727Hbj91RtXqlah4EdVqSyIajO1cfv1MqzTk4SQ2Ipyu8lYEibBmLioYMlbybVrxeYnEw7gLMrUXeZ1m2cmEPmUNr0Qi6d5BY3FhZCkYS8iLGbsiYBosvdhEaMgY+oMGGIS4UHrjxci0tmLMtgS6TxjHtpUvL0wWJgTbEsoGGe8SMNRhacRg6oblKOVwyEBj1RJiCr3Zen+6jI6Ik4970T0Y14cSd+okYBYaE5RINocwmzvQt/pWdToga6lnKJAtDkArYZJgXhMimTApxfFpBF9KuDordd9qrQJXUkm82H4taKS+VB5k1kyIP2eShYUxcrGYGFIB8Tul2O3S2aywv6cYz9OB2yw0YuTSpY2Ei85QkiZrtoo+cP8ZDqZhgCP+F8Kk77aJNTQRvlD10Pb8lDBZHlo7yIWmOjo/bI8Jx8byPECm8iH3uSEffm3858LSoLrpi3+mcS7e57rP5HX69BI7ID34jxPpJ7DqodxSMk70/Vz+umB/+GBv9HkI1uzfxLJAAAAAElFTkSuQmCC"
self.tool = vrImmersiveUiService.createTool("vrFlashlightTool")
self.tool.setText("Flashlight")
self.tool.setCheckable(True)
self.tool.setOnOffIconData(onIcon,offIcon)
self.tool.signal().checked.connect(self.switchOn)
self.tool.signal().unchecked.connect(self.switchOff)
self.tool.hideAway(True)
def deleteMenu(self):
vrImmersiveUiService.deleteTool(self.tool)
def getGeo(self):
if not self.geo is None and self.geo.isValid():
return self.geo
self.createGeo()
return self.geo
def createGeo(self):
for node in findNodes("VR_Flashlight"):
node.getParent().subChild(node)
self.geo = createNode("Transform3D","VR_Flashlight",False)
self.trans = createNode("Transform3D","FlashlightPos",self.geo,False)
handle = createCylinder(150,20,32,True,True,True,.1,.1,.1)
self.flashlightHandle = vrNodeService.getNodeFromId(handle.getID())
head = createCylinder(20,22,32,True,True,True,.3,.3,.3)
light = createLight("USpotLight")
light.fields().setReal32("intensity",30000000)
light.fields().setBool("visualizationVisible",False)
light.fields().setReal32("groundShadowIntensity",0.0)
setTransformNodeRotation(light,-90,0,0)
setTransformNodeTranslation(light ,0,-110-20,-10,False)
setTransformNodeTranslation(head ,0,-85-20,-10,False)
setTransformNodeTranslation(handle,0, 0-20,-10,False)
moveNode(handle,handle.getParent(),self.trans)
moveNode(head,handle.getParent(),self.trans)
moveNode(light,light.getParent(),self.trans)
self.geo.setActive(False)
def removeGeo(self):
subChilds(self.geo.getParent(),[self.geo])
def updateFlashlight(self, device):
if device.getVisualizationMode() != self.visualizationMode:
self.adjustFlashlight(device)
self.visualizationMode = device.getVisualizationMode()
def adjustFlashlight(self, device):
if device.getVisualizationMode() == 1:
self.setHandTransform()
self.flashlightHandle.setVisibilityFlag(True)
else:
self.setControllerTransform()
self.flashlightHandle.setVisibilityFlag(False)
def setHandTransform(self):
setTransformNodeTranslation(self.trans,0,-25,100,False)
setTransformNodeRotation(self.trans,110,0,0)
def setControllerTransform(self):
setTransformNodeTranslation(self.trans,0,-10,130,False)
setTransformNodeRotation(self.trans,45,0,0)
flashlight = Flashlight()
label = QtWidgets.QLabel(VREDPluginWidget)
label.setAlignment(QtCore.Qt.AlignmentFlag.AlignCenter)
label.setScaledContents(True)
label.setText("Python VR flashlight avatars tool\n" + __file__)
VREDPluginWidget.layout().addWidget(label)