Rope.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. from panda3d.core import *
  2. import types
  3. class Rope(NodePath):
  4. """
  5. This class defines a NURBS curve whose control vertices are
  6. defined based on points relative to one or more nodes in space, so
  7. that the "rope" will animate as the nodes move around. It uses
  8. the C++ RopeNode class to achieve fancy rendering effects like
  9. thick lines built from triangle strips.
  10. """
  11. showRope = ConfigVariableBool('show-rope', True, \
  12. "Set this to false to deactivate the display of ropes.")
  13. def __init__(self, name = 'Rope'):
  14. self.ropeNode = RopeNode(name)
  15. self.curve = NurbsCurveEvaluator()
  16. self.ropeNode.setCurve(self.curve)
  17. NodePath.__init__(self, self.ropeNode)
  18. self.name = name
  19. self.order = 0
  20. self.verts = []
  21. self.knots = None
  22. def setup(self, order, verts, knots = None):
  23. """This must be called to define the shape of the curve
  24. initially, and may be called again as needed to adjust the
  25. curve's properties.
  26. order must be either 1, 2, 3, or 4, and is one more than the
  27. degree of the curve; most NURBS curves are order 4.
  28. verts is a list of (NodePath, point) tuples, defining the
  29. control vertices of the curve. For each control vertex, the
  30. NodePath may refer to an arbitrary node in the scene graph,
  31. indicating the point should be interpreted in the coordinate
  32. space of that node (and it will automatically move when the
  33. node is moved), or it may be the empty NodePath or None to
  34. indicate the point should be interpreted in the coordinate
  35. space of the Rope itself. Each point value may be either a
  36. 3-tuple or a 4-tuple (or a VBase3 or VBase4). If it is a
  37. 3-component vector, it represents a 3-d point in space; a
  38. 4-component vector represents a point in 4-d homogeneous
  39. space; that is to say, a 3-d point and an additional weight
  40. factor (which should have been multiplied into the x y z
  41. components).
  42. verts may be a list of dictionaries instead of a list of
  43. tuples. In this case, each vertex dictionary may have any of
  44. the following elements:
  45. 'node' : the NodePath indicating the coordinate space
  46. 'point' : the 3-D point relative to the node; default (0, 0, 0)
  47. 'color' : the color of the vertex, default (1, 1, 1, 1)
  48. 'thickness' : the thickness at the vertex, default 1
  49. In order to enable the per-vertex color or thickness, you must
  50. call rope.ropeNode.setUseVertexColor(1) or
  51. rope.ropeNode.setUseVertexThickness(1).
  52. knots is optional. If specified, it should be a list of
  53. floats, and should be of length len(verts) + order. If it
  54. is omitted, a default knot string is generated that consists
  55. of the first (order - 1) and last (order - 1) values the
  56. same, and the intermediate values incrementing by 1.
  57. """
  58. self.order = order
  59. self.verts = verts
  60. self.knots = knots
  61. self.recompute()
  62. def recompute(self):
  63. """Recomputes the curve after its properties have changed.
  64. Normally it is not necessary for the user to call this
  65. directly."""
  66. if not self.showRope:
  67. return
  68. numVerts = len(self.verts)
  69. self.curve.reset(numVerts)
  70. self.curve.setOrder(self.order)
  71. defaultNodePath = None
  72. defaultPoint = (0, 0, 0)
  73. defaultColor = (1, 1, 1, 1)
  74. defaultThickness = 1
  75. useVertexColor = self.ropeNode.getUseVertexColor()
  76. useVertexThickness = self.ropeNode.getUseVertexThickness()
  77. vcd = self.ropeNode.getVertexColorDimension()
  78. vtd = self.ropeNode.getVertexThicknessDimension()
  79. for i in range(numVerts):
  80. v = self.verts[i]
  81. if isinstance(v, types.TupleType):
  82. nodePath, point = v
  83. color = defaultColor
  84. thickness = defaultThickness
  85. else:
  86. nodePath = v.get('node', defaultNodePath)
  87. point = v.get('point', defaultPoint)
  88. color = v.get('color', defaultColor)
  89. thickness = v.get('thickness', defaultThickness)
  90. if isinstance(point, types.TupleType):
  91. if (len(point) >= 4):
  92. self.curve.setVertex(i, VBase4(point[0], point[1], point[2], point[3]))
  93. else:
  94. self.curve.setVertex(i, VBase3(point[0], point[1], point[2]))
  95. else:
  96. self.curve.setVertex(i, point)
  97. if nodePath:
  98. self.curve.setVertexSpace(i, nodePath)
  99. if useVertexColor:
  100. self.curve.setExtendedVertex(i, vcd + 0, color[0])
  101. self.curve.setExtendedVertex(i, vcd + 1, color[1])
  102. self.curve.setExtendedVertex(i, vcd + 2, color[2])
  103. self.curve.setExtendedVertex(i, vcd + 3, color[3])
  104. if useVertexThickness:
  105. self.curve.setExtendedVertex(i, vtd, thickness)
  106. if self.knots != None:
  107. for i in range(len(self.knots)):
  108. self.curve.setKnot(i, self.knots[i])
  109. self.ropeNode.resetBound(self)
  110. def getPoints(self, len):
  111. """Returns a list of len points, evenly distributed in
  112. parametric space on the rope, in the coordinate space of the
  113. Rope itself."""
  114. result = self.curve.evaluate(self)
  115. startT = result.getStartT()
  116. sizeT = result.getEndT() - startT
  117. numPts = len
  118. ropePts = []
  119. for i in range(numPts):
  120. pt = Point3()
  121. result.evalPoint(sizeT * i / float(numPts - 1) + startT, pt)
  122. ropePts.append(pt)
  123. return ropePts