This script shows
GeometryAccess
class and createLineTexCoords
method below.findLineGeos
, findGeos
and findGeosRecursive
. 1 """ This script creates UV coordinates for line geometries
2 in the scene, so that a stipple pattern can be created
3 with a transparency texture.
4 For demonstration purposes an example line geometry is
5 loaded.
6 """
7
8 newScene()
9
10 class GeometryAccess(object):
11 """ Helps accessing primitives and vertex data of a vrdGeometryNode.
12
13 Args:
14 geo (vrdGeometryNode): The geometry node.
15 """
16 def __init__(self, geo):
17 if geo.isValid():
18 self.__positions = geo.getPositions()
19 self.__indices = geo.getIndices()
20 self.__primType = geo.getPrimitiveType()
21 else:
22 self.__positions = []
23 self.__indices = []
24 self.__primType = None
25
26 def isLineGeometry(self):
27 """
28 Returns:
29 Whether the geometry is a line geometry.
30 """
31 return GeometryAccess.isLineType(self.__primType)
32
33 def isLineType(primType):
34 """
35 Returns:
36 Whether the type is a line primitive type.
37 """
38 return primType in (vrGeometryTypes.Lines, vrGeometryTypes.LineStrip)
39
40
41 def getPosition(self, vertexIndex):
42 """
43 Args:
44 vertexIndex (int): The vertex index in range from 0 to N-1
45 where N is the vertex count.
46 Returns:
47 3d vertex position.
48 """
49 return QVector3D(self.__positions[3*vertexIndex],
50 self.__positions[3*vertexIndex+1],
51 self.__positions[3*vertexIndex+2])
52
53
54 def getPrimitiveVertexIndices(self, primId):
55 """
56 Args:
57 primId (int): The primitive index in range from 0 to N-1
58 where N is the primitive count.
59 Returns:
60 A list of vertex indices of a primitive: 3 indices for a
61 triangle, 2 for a line primitives, 1 for a point primitive.
62 """
63 if self.__primType == vrGeometryTypes.Points:
64 v0 = primId
65 return [self.__indices[v0]]
66 elif self.__primType == vrGeometryTypes.Lines:
67 v0 = primId * 2
68 v1 = primId * 2 + 1
69 return [self.__indices[v0], self.__indices[v1]]
70 elif self.__primType == vrGeometryTypes.LineStrip:
71 v0 = primId
72 v1 = primId + 1
73 return [self.__indices[v0], self.__indices[v1]]
74 elif self.__primType == vrGeometryTypes.Triangles:
75 v0 = primId * 3
76 v1 = primId * 3 + 1
77 v2 = primId * 3 + 2
78 return [self.__indices[v0], self.__indices[v1], self.__indices[v2]]
79 else:
80 return []
81
82
83 # Helper methods to find line geometries in the scene tree.
84
85 def findGeosRecursive(node, geos, predicate):
86 """ Recursively traverses the scenegraph starting at node
87 and collects geometry nodes which can be filtered
88 with a predicate.
89 Args:
90 node (vrdNode): Currently traversed node
91 geos (list of vrdGeometryNode): List of collected geometry nodes
92 predicate (function): None or predicate(vrdGeometryNode)->bool
93 """
94 geo = vrdGeometryNode(node)
95 if geo.isValid():
96 if predicate is None or predicate(geo):
97 geos.append(geo)
98 # stop traversing the tree
99 else:
100 # traverse the children
101 for child in node.getChildren():
102 findGeosRecursive(child, geos, predicate)
103
104 def findGeos(root, predicate=None):
105 """ Wraps findGeosRecursive to return the list of geometry nodes.
106 """
107 geos = []
108 findGeosRecursive(vrdNode(root), geos, predicate)
109 return geos
110
111
112 def findLineGeos(root):
113 predicate = lambda geo : GeometryAccess.isLineType(geo.getPrimitiveType())
114 lines = findGeos(root, predicate)
115 return lines
116
117
118 def createLineTexCoords(node):
119 """Assigns texture coordinates (u, 0) to a given line geometry, with u
120 going from 0.0 (begin of line sequence) to "length" (end of line sequence).
121 The coordinates along the line are calculated from the lengths of the
122 3D lines, and scaled such that the texture width corresponds to 100 mm
123 in the scene (world-scale texture coordinates)
124
125 Args:
126 node (vrdNode): A line geometry node.
127 It is assumed that the geometry stores the lines
128 in the same order as they are concatenated in 3D.
129 """
130
131 geo = vrdGeometryNode(node)
132 geoAccess = GeometryAccess(geo)
133 if not geoAccess.isLineGeometry():
134 return
135
136 # Calculate lengths of all line segments, from start vertex
137 # to each vertex along the line geometry.
138 #
139 # v0----v1----v2----v3
140 # |
141 # -------|
142 # ------------|
143 # -------------------|
144
145 vertexCount = geo.getVertexCount()
146 segmentLengths = [0.0] * vertexCount
147 totalLength = 0.0
148
149 # The world scale factor of the geometry is needed to
150 # calculate the actual world length of the lines.
151 sx, sy, sz = toNode(geo.getObjectId()).getWorldScale()
152 scale = QVector3D(sx, sy, sz)
153
154 lineCount = geo.getPrimitiveCount()
155 for lineId in range(0, lineCount):
156 v0, v1 = geoAccess.getPrimitiveVertexIndices(lineId)
157 p0 = geoAccess.getPosition(v0)
158 p1 = geoAccess.getPosition(v1)
159 lineLength = ((p1 - p0) * scale).length()
160 segmentLengths[v0] = totalLength
161 segmentLengths[v1] = totalLength + lineLength
162 totalLength += lineLength
163
164 # Create world-scale texture coordinates from list of lengths:
165
166 # 1 in UV space corresponds to 100mm in scene units
167 mmToUVUnit = 1.0 / 100.0
168 # Pre-allocate flat list of 2d-coordinates for each vertex
169 texCoords2f = [0.0] * (vertexCount * 2)
170
171 for i in range(0, vertexCount):
172 u = segmentLengths[i] * mmToUVUnit
173 texCoords2f[i * 2] = u
174 # v-coordinate stays 0.0
175
176 geo.setTexCoords(texCoords2f)
177
178
179 ###########################################################
180
181 # Load example line geometry
182 loadGeometry("$VRED_EXAMPLES/geo/curve.osb")
183
184 # Find all line geometries in scenegraph
185 root = getRootNode()
186 lines = findLineGeos(root)
187 print ("Found line geometries:", len(lines))
188
189 # Create the texture coordinates
190 for line in lines:
191 createLineTexCoords(line)
192