Skip to content

Flat RopeNode: Breaks and Overlaps #1325

@ArsThaumaturgis

Description

@ArsThaumaturgis

Description

A moving rope-node, with the "tape" render-mode applied, can produce small overlaps and breaks along its course. This is most especially the case when it turns acutely, I find.

Steps to Reproduce

The following program demonstrates the effect, on my machine at least. To test, simply run the program--you should see a flat rope-node moving in a circle of varying diameter, and triangular breaks and overlaps appearing. (The latter made visible via transparency and a lack of depth-testing)

from direct.showbase.ShowBase import ShowBase

from panda3d.core import Vec3, Vec4, NodePath, RopeNode, NurbsCurveEvaluator

import math

from panda3d import __version__ as pandaVersion
print (pandaVersion)

import sys
print (sys.version)

class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        # A black backdrop to better show the effect
        self.win.setClearColor(Vec4(0, 0, 0, 1))

        # Our rope and its curve!
        self.ropeNode = RopeNode("rope")
        self.curve = NurbsCurveEvaluator()
        self.ropeNode.setCurve(self.curve)

        # Make the rope a flat surface, and set its width
        self.ropeNode.setRenderMode(RopeNode.RM_tape)
        self.ropeNode.setThickness(3)

        # I'm not sure that these are required, but I'll leave them in just in case
        self.ropeNode.setNormalMode(RopeNode.NM_none)
        self.ropeNode.setTubeUp(Vec3(0, 0, 1))

        # Set set up the curve and our number of points
        self.curve.reset(7)

        # Create and arrange a NodePath for our rope
        self.ropeNP = NodePath(self.ropeNode)
        self.ropeNP.setY(25)
        self.ropeNP.setP(90)
        self.ropeNP.reparentTo(render)

        # This makes the rope semi-transparent and prevents depth-testing from interfering, as in the original case
        self.ropeNP.setAlphaScale(0.5)
        self.ropeNP.setTransparency(True)
        self.ropeNP.setDepthTest(False)

        # For the purposes of this demonstrative program, we'll just have the rope spin around in a circle.
        # These next things, then, are elements that control the points of the curve:
        #  a list of points, a speed-value, and a circle-size (which changes)
        self.positionList = []

        self.angle = 0

        self.speed = 5

        self.circleSize = 5
        self.maxCircleSize = 5
        self.minCircleSize = 1
        self.circleSizeDir = 1

        # And finally, an update task in which to update our curve
        self.updateTask = self.taskMgr.add(self.update, "update task")

    def update(self, task):
        dt = self.clock.getDt()

        # Vary the size of the circle of the rope's movement, to show different aspects of the effect produced
        self.circleSize += self.circleSizeDir * 1.5 * dt
        if self.circleSizeDir > 0 and self.circleSize > self.maxCircleSize:
            self.circleSize = self.maxCircleSize
            self.circleSizeDir = -1
        elif self.circleSizeDir < 0 and self.circleSize < self.minCircleSize:
            self.circleSize = self.minCircleSize
            self.circleSizeDir = 1

        # Accumulate a circular angle, and from that calculate the current position on the circle
        self.angle += self.speed * dt

        pos = Vec3(math.sin(self.angle) * self.circleSize, math.cos(self.angle) * self.circleSize, 0)

        # Update the list of points:
        numPoints = len(self.positionList)
        if numPoints == 0:
            # If there are no points yet, just add the current one
            self.positionList.append(pos)
        else:
            # Otherwise, if the current point is sufficiently far from the last, add it
            lastPt = self.positionList[-1]
            diff = pos - lastPt
            lastSegmentDist = diff.length()
            testDist = 1.5
            if lastSegmentDist > testDist:
                self.positionList.append(pos)

                # Prevent the list from holding too many points
                while len(self.positionList) > 8:
                    self.positionList.pop(0)

        # And finally, update the curve!
        # The first vertex is always the current point, and subsequent vertices
        #  take their positions from the point-list
        self.curve.setVertex(0, pos)
        for index, pt in enumerate(self.positionList[-1:-(len(self.positionList)-1):-1]):
            self.curve.setVertex(index+1, pt)

        return task.cont


app = Game()
app.run()

Screenshot from 2022-06-23 11-17-21

Environment

  • Operating system: Ubuntu Linux 18.04.6
  • System architecture: 64-bit
  • Panda3D version: 1.10.11
  • Installation method: pip, I believe.
  • Python version (if using Python): 3.6.9
  • Compiler (if using C++): N/A

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions