教程 10:如何使用服务中的 Qt 信号

了解如何使用服务中的 Qt 信号。

下载示例脚本

跳转到脚本示例

下载教程 PDF

视频字幕:大家好,欢迎学习这一面向 VRED Pro 的 Python 脚本教程。我叫 Christopher,今天我将介绍如何在 VRED 中使用 Qt 信号对事件做出反应。

那么,什么是 Qt 信号?Qt 信号是在 Qt 框架中实现的,VRED 也使用此框架。信号是在软件不同部分之间进行通信的方式,例如,用户界面可以与程序的逻辑层进行通信并交换信息。在 VRED 中,如果任何数据发生更改(或者更具体地说,如果发生用户可能要对其做出反应的事件),则使用相同方法向 Python 脚本发出信号。编写脚本时,可以连接到 VRED 服务的信号,并且可以在该信号被触发时执行操作。

此情况的常见用例有哪些?在 API v2 中,Autodesk 引入了许多可用于各种用途的信号。例如,标注服务中有一些在创建或删除标注时向脚本发送的信号。还有一些在场景图形中添加或删除节点时发出的信号,如果您希望在场景图形更改时自动重建查找缓存,这可能会很有帮助。甚至有一些在验证所有灯光时发出的信号。

VR 会话使用信号来告知何时用户加入或离开会话。可以在自定义用户界面中显示该信息,也可以在三维空间中显示连接的 VR 用户。这六个示例来自 Autodesk 官方示例,显示了如何使用信号来更新 VR 会话的概览图以及将用户放置在三维空间中。

我们来看看如何在自己的脚本中使用信号。信号是 API v2 服务的一部分,因此您可以浏览文档以查找提供信号的任何服务。例如,vrAnnotationService 文档中有一小节列出了信号及其参数。

在此示例中,我将连接到标注服务中的这些信号。首先,我们为每个信号创建回调函数。这些是每次触发相应信号时调用的函数。在本例中,当创建、添加、删除标注以及更改标注可见性时,会调用回调函数。

相关文档介绍了信号传递的数据。例如,createAnnotation 信号传递创建的标注,可见性参数告知标注是否设置为可见。在接下来的行中,我们使用信号的连接函数来连接到这些信号,并使用回调函数的名称作为参数。当我们执行此代码并添加标注时,应该会触发信号并在终端输出消息,确实如此。

接下来,我想介绍如何侦听场景图形中的更改以自动触发查找缓存重建。如果您的一些脚本依赖于在场景图形中动态查找节点,则使用查找缓存可以提高节点查找操作的速度和性能。在此示例中,我们创建了使用输入参数“nodes”的回调函数“nodesChanged”,用于列出已更改的所有节点。

在此函数中,我们首先清除缓存,然后重建缓存。在接下来的几行中,我们连接到一些信号,用于告知是否在场景图形中添加或移除了任何节点,即“nodes added”和“nodes removed”信号。现在,当在场景图形中执行此代码并更改节点时,它将始终自动为我们重建查找缓存。

除了服务中的信号外,VRED 还有其他有用的信号可用于侦听系统消息。例如,您可以在创建新场景时或保存场景之前做出反应。在最后一个示例中,我们连接到所谓的 vrMessageService 来侦听所有种类的系统消息。有关 vrController 模块的文档提供了这些消息的完整列表。

每次发生系统事件时,vrMessageService 都会发送代码,这些代码会转换为这些系统消息之一。在此代码示例中,每当 vrMessageService 触发信号时,会在终端上输出相应的消息代码。例如,如果我们选择摄影机,则将触发“SELECTED_CAMERA”消息。

好了!今天就到这里。希望您现在能够在 VRED 中使用 Qt 信号。感谢您参加本课程,下次见!


Python 代码示例

下面是教程 10:如何在服务中使用 Qt 信号视频随附的 Python 脚本示例。

提示:

要下载这些压缩文件,请单击此处

service_signals.py

# Example 1.0
# Connecting to service signals 
# vrAttachmentService
def annotationCreatedCallback(annotation):
    print("Created annotation", annotation)
    
def annotationAddedCallback():
    print("Added annotation")
    
def annotationsDeletedCallback():
    print("Deleted annotation")
    
def annotationsShowChangedCallback(visible):
    print("Annotations are visible: ", visible)

`vrAnnotationService`.annotationCreated.connect(annotationCreatedCallback)
`vrAnnotationService`.annotationsAdded.connect(annotationAddedCallback)
`vrAnnotationService`.annotationsDeleted.connect(annotationsDeletedCallback)
`vrAnnotationService`.showAnnotationsChanged.connect(annotationsShowChangedCallback)

# vrNodeService
def nodesChanged(nodes):
    print("Nodes changed: Rebuilding find cache...")
    vrNodeService.clearFindCache()
    vrNodeService.initFindCache()

vrNodeService.nodesAdded.connect(nodesChanged)
vrNodeService.nodesRemoved.connect(nodesChanged)

# Listening to general object changes
def propertyChanged(obj, propertyName):
   print("object name: {}, property name: {}".format(obj.getName(), propertyName))

vrObjectService.propertyChanged.connect(propertyChanged)

service_signals_sessions.py

# https://knowledge.autodesk.com/support/vred-products/learn-explore/caas/CloudHelp/cloudhelp/2021/ENU/VRED/files/Python-Documentation/Python-Examples/VRED-Python-Documentation-Python-Examples-Visualize-user-positions-html.html
# This scripts shows an overview of user positions in a collaboration sesion
class UserMap(vrAEBase):
    
    def __init__(self):
        vrAEBase.__init__(self)
        self.spheres = {}
        self.addLoop()
        # callback sesson start/stop
        vrSessionService.sessionJoined.connect(self.started)
        vrSessionService.sessionLeft.connect(self.ended)
        # callback user joins/leaves session
        vrSessionService.userArrives.connect(self.userArrived)
        vrSessionService.userLeaves.connect(self.userLeaves)
        
    def loop(self):
        # this is my local camera position
        myPos = getTransformNodeTranslation(vrSessionService.getUser().getHeadNode(),True)
        for user in vrSessionService.getRemoteUsers():
            sphere = self.spheres[user.getUserId()]
            # this is the users head transformation node
            pos = getTransformNodeTranslation(user.getHeadNode(),True)
            # move indicator for user position
            setTransformNodeTranslation(sphere,(pos.x()-myPos.x())/100,(pos.y()-myPos.y())/100,-500,False)
   
    def started(self):
        self.group = createNode("Group", "UserMap", vrCameraService.getActiveCamera())
        self.plane = createCylinder(2, 100, 50, True, True, True, .0, .1, .0)
        self.setTransparent(self.plane)
        addChilds(self.group,[self.plane])
        color = vrSessionService.getUser().getUserColor()
        sphere = createSphere(3, 2, color.redF(), color.greenF(), color.blueF())
        addChilds(self.group,[sphere])
        setTransformNodeTranslation(sphere,0,0,-500,False)
        setTransformNodeRotation(self.plane, 90, 0, 0)
        setTransformNodeTranslation(self.plane, 0, 0, -500, False)
        self.setActive(True)
        
    def ended(self):
        subChilds(self.group,[self.plane])
        subChilds(vrCameraService.getActiveCamera(),[self.group])
        self.setActive(False)
        
    def userArrived(self,user):
        color = user.getUserColor()
        sphere = createSphere(2, 2, color.redF(), color.greenF(), color.blueF())
        addChilds(self.group,[sphere])
        self.spheres[user.getUserId()] = sphere
        
    def userLeaves(self,user):
        sphere = self.spheres[user.getUserId()]
        subChilds(self.group,[sphere])
        
    def setTransparent(self,node):
        node.getMaterial().fields().setVec3f("seeThrough",.95,.95,.95)

map = UserMap()

vr_message_service.py

# Utilizing `vrMessageService`
def receivedMessage(message_id, args):
    messages = (
        'VRED_MSG_ARGV',
        'VRED_MSG_CHANGED_CAMERA_UP',
        'VRED_MSG_CHANGED_MATERIAL',
        'VRED_MSG_CHANGED_PB_PARAMETERS',
        'VRED_MSG_CHANGED_SCENEGRAPH',
        'VRED_MSG_CONVERT_OSF_FILE',
        'VRED_MSG_DESELECTED_NODE',
        'VRED_MSG_EXPORTED_FILE',
        'VRED_MSG_IDLE',
        'VRED_MSG_IMPORTED_FILE',
        'VRED_MSG_INIT',
        'VRED_MSG_KEY_PRESSED',
        'VRED_MSG_KEY_RELEASED',
        'VRED_MSG_LOADED_GEOMETRY',
        'VRED_MSG_LOOP',
        'VRED_MSG_NEW_SCENE',
        'VRED_MSG_NONE',
        'VRED_MSG_PRENEW_SCENE',
        'VRED_MSG_PRE_QUIT',
        'VRED_MSG_PROJECT',
        'VRED_MSG_PROJECT_LOADED',
        'VRED_MSG_PROJECT_MERGED',
        'VRED_MSG_SAVED_GEOMETRY',
        'VRED_MSG_SELECTED_CAMERA',
        'VRED_MSG_SELECTED_LIGHT',
        'VRED_MSG_SELECTED_MATERIAL',
        'VRED_MSG_SELECTED_NODE',
        'VRED_MSG_SWITCH_MATERIAL_CHANGED',
        'VRED_MSG_UPDATE_UI',
        'VRED_MSG_USER',
        )

    # Print the message that was signaled
    for message in messages:
        if message_id == getattr(vrController, message):
            print(message)

    # Listen specifically to the SELECTED CAMERA message
    if message_id == vrController.VRED_MSG_SELECTED_CAMERA:
        print("Camera selected!")

`vrMessageService`.message.connect(receivedMessage)