Create texture coordinates for line geometries

This script shows

lineGeometry-texCoords.py

  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