Hi, very new to Panda3d (using 1.10.3) and running into a confusing issue. I am trying to add motion trails to objects in my world, and running into a problem where any object that is rendered outside of the camera view prevents any motion trails inside the camera view from rendering, regardless of whether the object outside the camera view had a motion trail attached to it.
I was unable to get the direct.motiontrail.MotionTrail class to work (anyone know what vertex fuction/context is, and how to use them to add vertices?), and so I have written my own. It just uses a task to poll the global coordinates of the attached object at a specified interval, and generates a GeomLinestrips line connecting all the points. When the maximum number of coordinates is reached, it discards the oldest one. Implementation is here:
from panda3d.core import *
from direct.task import Task
from direct.showbase.DirectObject import DirectObject
from collections import deque
class MotionTrail(DirectObject):
task_added = False
motion_trail_list = [ ]
motion_trail_task_name = "motion_trail_task"
def __init__(self, leading_nodepath):
self.vertex_max = 50
self.leading_nodepath = leading_nodepath
self.center = NodePath("center")
self.center.setPos(0,0,0)
self.verticies = deque([])
self.geom_vertex_format = GeomVertexFormat.getV3c4()
self.renderThickness = 1
self.update_interval_s = 0.1
self.last_update_s = 0
self.prim = GeomLinestrips(Geom.UHStatic)
self.geom_vertex_data = GeomVertexData("Motion Trail", self.geom_vertex_format, Geom.UHStatic)
self.geom_vertex_data.setNumRows(self.vertex_max)
geom = Geom(self.geom_vertex_data)
geom.addPrimitive(self.prim)
geomNode = GeomNode("Motion Trail Geom Node")
geomNode.addGeom(geom)
self.nodePath = render.attachNewNode(geomNode)
self.nodePath.setRenderModeThickness(self.renderThickness)
MotionTrail.motion_trail_list.append(self)
if MotionTrail.task_added == False:
# taskMgr.add (self.motion_trail_task, "motion_trail_task", priority = 50)
taskMgr.add(self.motion_trail_task, MotionTrail.motion_trail_task_name)
self.acceptOnce("clientLogout", remove_task)
MotionTrail.task_added = True
def renderTrail(self):
if len(self.verticies) < 2:
return
self.prim.clearVertices()
vertex = GeomVertexWriter(self.geom_vertex_data, "vertex")
color = GeomVertexWriter(self.geom_vertex_data, "color")
print("########################################")
for index, vertice in enumerate(self.verticies):
print("x: " + str(vertice.x) + " y: " + str(vertice.y) + " z: " + str(vertice.z))
vertex.addData3f(vertice.x, vertice.y, vertice.z)
color.addData4f(1,1,1,1) #max(float(self.vertex_max - index), 1)/self.vertex_max
print("########################################")
self.prim.addConsecutiveVertices(0, len(self.verticies))
self.prim.closePrimitive()
def motion_trail_task(self, task):
if task.time - self.last_update_s > self.update_interval_s:
self.last_update_s = task.time
for motion_trail in MotionTrail.motion_trail_list:
motion_trail.verticies.append(motion_trail.leading_nodepath.getPos(motion_trail.center))
if len(motion_trail.verticies) > motion_trail.vertex_max:
motion_trail.verticies.popleft()
motion_trail.renderTrail()
return Task.cont
def destroy(self):
MotionTrail.motion_trail_list.remove(self)
if len(MotionTrail.motion_trail_list) == 0 and MotionTrail.task_added:
remove_task()
def IsInView(self, other_node):
lensBounds = base.cam.node().getLens().makeBounds()
bounds = other_node.getBounds()
bounds.xform(other_node.getParent().getMat(base.cam))
return lensBounds.contains(bounds)
##########################END MOTION TRAIL CLASS##########################
def remove_task():
if MotionTrail.task_added:
total_motion_trails = len(MotionTrail.motion_trail_list)
if total_motion_trails > 0:
print("warning: %d motion trails still exist when motion trail task is removed" % (total_motion_trails))
MotionTrail.motion_trail_list = [ ]
taskMgr.remove(MotionTrail.motion_trail_task_name)
print("MotionTrail task removed")
MotionTrail.task_added = False
return
This works fine as long as all objects attached to ‘render’ are well within the view, but starts to falter when they are close to the edge and stops rendering outright when they are no longer visible. Here is a sample program that illustrates the issue:
from direct.showbase.ShowBase import ShowBase
base = ShowBase()
from motion_trail import MotionTrail
class World():
def __init__(self):
base.setBackgroundColor(0, 0, 0)
base.disableMouse()
camera.setPos(0, 0, 90)
camera.setHpr(0, -90, 0)
self.visible_model = loader.loadModel("models/sphere")
self.visible_motion_trail = MotionTrail(self.visible_model)
self.visible_model.reparentTo(render)
self.visible_model.setPos(10, 0, 0)
self.visible_model.posInterval(5, (-10, 0, 0)).start()
self.invisible_model = loader.loadModel("models/sphere")
self.invisible_model.reparentTo(render)
self.invisible_model.setPos(40, 0, 0)
world = World()
base.run()
Setting the “invisible model” position to 40 will have the visible model traverse the screen without a trail. Setting the “invisible model” position to 30 will have it right at the edge of the screen, and the visible model will have a render trail that eventually cuts out. Setting the “invisible model” position to 20 will have the render trail stay with the visible model for its entire traversal, working as intended. Setting the “invisible model” position at 40 but no parenting it to ‘render’ will have the motion trail work as intended.
Any help or advice on how to solve this issue? Thanks.