Physics basic collision example¶
This example demonstrates how to use the Physics collision pipeline in a scene. It involves adding kinematic actors that can be moved and react to collisions with other nodes. VRED currently does not support the creation of dynamic actors, so the only way to interact with the physics simulation is by adding kinematic actors. No forces can be applied to these actors, but they can be moved around in the scene and react to collisions with other nodes.
The provided Python script demonstrates the usage of the Physics collision pipeline in a scene. It involves adding kinematic actors that can be moved and react to collisions with other nodes. The script highlights the colliding nodes by rendering them with an override material. Each registered node has a different highlight material assigned in the highlight function. To begin, specific nodes are fetched from the scene graph, such as “Teddy_Bear”, “Teddy_Bear2”, “Speedshape”, “Cloth_Example”, and “VRED_Logo”, which will be assigned collision objects.
The script then prepares the physics configurations for these nodes, determining the type of collision shape that will be built for each node. Next, the nodes are added to the service along with their configurations, and the service is set to active to start the collision pipeline. Additionally, the script attempts to connect to the NVidia debugger if it is already running.
The script creates a map for bookkeeping the highlight state of the nodes, which uses reference counting to track the number of collisions a node is involved in. This prevents flickering when a collision with one object ends while a collision with another object is still ongoing. The script defines a highlight function that selects a different material to highlight each node when it collides. The function utilizes the override material feature to achieve the highlighting effect.
Furthermore, the script registers three callback functions and connects them to the started, stopped, and continues signals of the service. The collisionStart function increments the counter for highlighting when a new collision event starts and turns on the highlighting for both nodes. The collisionStopped function decrements the counter when a collision between two objects ends and removes the highlighting. The collisionContinues function ensures that the highlighting is still applied while the collision is ongoing.
Finally, the script connects the callbacks to the service.
1 # This example shows how to use the Physics collision pipeline.
2 # We add a few nodes as kinematic actors, so that we can move them
3 # in the scene and react on collisions between them.
4 #
5 # The only reaction on collision is that we render the colliding nodes
6 # with an override material to highlight it. Each registered node has
7 # a different highlight material assigned in the highlight function.
8
9 # The 'speedshape' node is animated. If the animation is played, the node
10 # will be moved from side to side and collide with the other nodes.
11
12
13 # First fetch some nodes from the scene graph that
14 # should get a collision object
15
16 teddy = vrNodeService.findNode("Teddy_Bear")
17 teddy2 = vrNodeService.findNode("Teddy_Bear2")
18 speedshape = vrNodeService.findNode("Speedshape")
19 cloth = vrNodeService.findNode("Cloth_Example")
20 logo = vrNodeService.findNode("VRED_Logo")
21
22 # The next step is creating collision shapes for the nodes we have collected.
23 # We use objects called 'configurations' to define how the collision shape should
24 # look like. Configurations are a collection of parameters that influence the way
25 # the collision shape is created.
26
27 # Now we prepare the physics configurations for the nodes. The configuration
28 # determines what kind of collsion shape is built for the node.
29 # Since it's not possible to have moving triangle meshes in the physics simulation,
30 # we have to approximate the geometry of the nodes with simpler shapes. We use
31 # a technique called 'convex decomposition' to split the geometry into multiple
32 # smaller convex hulls. This is a good compromise between accuracy and performance.
33 convexDecompConf = vrdPhysicsConvexConfig()
34
35 # After the configuration is created, we can change its properties to fine tune
36 # the collsion shape creation. In this case we increase the maximun number of
37 # convex hulls the algorithm is allowed to create from the default 64 to 256 to give
38 # it more freedom to aproximate the geometry.
39 convexDecompConf.setMaxNumberOfConvexHulls(256)
40
41 # This is the standard configuration for a convex hull.
42 convexHullConf = vrdPhysicsHullConfig()
43
44 # Here we have a special case of convex hull. If the bounding box option is set,
45 # we create a convex hull for the bounding box of the object. This is extremely fast and
46 # results in an object aligne bounding box collision shape.
47 boxConf = vrdPhysicsHullConfig()
48 boxConf.setUseBoundingBox(True)
49
50 # Add the nodes to the service along with their configurations.
51 vrPhysicsService.addKinematicObject(teddy, convexDecompConf)
52 vrPhysicsService.addKinematicObject(speedshape, convexHullConf)
53 vrPhysicsService.addKinematicObject(cloth, convexDecompConf)
54 vrPhysicsService.addKinematicObject(logo, convexDecompConf)
55 vrPhysicsService.addKinematicObject(teddy2, boxConf)
56
57 # The service needs to be set to 'active' to start the collision pipeline.
58 vrPhysicsService.setActive(True)
59
60 # Here we try to connect to the NVidia debugger in case it's already running.
61 vrPhysicsService.connectDebugger()
62
63
64 # A bit of cleanup when new scene is executed.
65 def newSceneCallback():
66 vrPhysicsService.collisionStarted.disconnect()
67 vrPhysicsService.collisionStopped.disconnect()
68 vrPhysicsService.collisionContinues.disconnect()
69
70 setNewSceneCB(newSceneCallback)
71
72 # This map is used for some bookkeeping of the highlight state of the nodes.
73 # It's a reference counting to track the number of collisions a node is involved in.
74 # This is to avoid flickering if a collision with one objects ends while a collision
75 # with another object is still ongoing. In this case the highlight function is called
76 # twice, once with 'True' (continues) and once with 'False' (stopped).
77 collisionState = {teddy:0, speedshape:0, cloth:0, logo:0, teddy2:0}
78
79 def highlight(node, enable):
80 # prevents reemoving highlighting when node collides with
81 # multiple nodes and one of the collisions ends
82 if not enable and collisionState[node] > 0:
83 return
84
85 # here we select a different material to highlight
86 # each node when it collides
87 if node.getName() == "Teddy_Bear":
88 material = "collision2"
89 elif node.getName() == "Teddy_Bear2":
90 material = "collision3"
91 elif node.getName() == "Cloth_Example":
92 material = "collision4"
93 elif node.getName() == "VRED_Logo":
94 material = "collision5"
95 else:
96 material = "collision1"
97
98 # to highlight the node, we use the override material feature
99 setNodeVisibilityFlags(node,
100 True,True,True,True,True,True,
101 True,True,True,True,enable,material)
102
103
104 # Here we register three callback functions and connect them
105 # to the started / stopped / continues signals of the service.
106
107 def collisionStart(nodeInfo):
108 # show the contactpoints (careful, printing the points causes
109 # a major slowdown)
110 #contactpoints = nodeInfo.getContactPoints()
111 #if len(contactpoints) > 0:
112 # for num, contact in enumerate(contactpoints):
113 # print("contact ({}): {} {} {}".format(num, contact.x(),
114 # contact.y(), contact.z()))
115
116 # We increment the counter for the highlighting when
117 # a new collision event starts
118 collisionState[nodeInfo.getCollidingRootNode1()] +=1
119 collisionState[nodeInfo.getCollidingRootNode2()] +=1
120
121 # Turn on the highlighting for both nodes
122 highlight(nodeInfo.getCollidingRootNode1(), True)
123 highlight(nodeInfo.getCollidingRootNode2(), True)
124
125 def collisionStopped(nodeInfo):
126 # Decrement the refount for the highlightin
127 # when a collsion between two objecs ends.
128 collisionState[nodeInfo.getCollidingRootNode1()] -=1
129 collisionState[nodeInfo.getCollidingRootNode2()] -=1
130
131 # Also remove the hightlighting.
132 highlight(nodeInfo.getCollidingRootNode1(), False)
133 highlight(nodeInfo.getCollidingRootNode2(), False)
134
135 def collisionContinues(nodeInfo):
136 # While the collsion is ongoing, we make sure that
137 # the highlighting is still applied. (This is not strictly
138 # necessary, but it's a good idea to make sure the highlighting is
139 # still active and not overwritten).
140 highlight(nodeInfo.getCollidingRootNode1(), True)
141 highlight(nodeInfo.getCollidingRootNode2(), True)
142
143
144 # Connect the callbacks to the service
145 vrPhysicsService.collisionStarted.connect(collisionStart)
146 vrPhysicsService.collisionStopped.connect(collisionStopped)
147 vrPhysicsService.collisionContinues.connect(collisionContinues)