Create texture coordinates for line geometries

This script shows

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