mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 01:44:06 -04:00
Enhancements to DirectSelection classes
This commit is contained in:
parent
021108c0e1
commit
d5b915eaad
@ -101,9 +101,7 @@ class DirectCameraControl(PandaObject):
|
||||
skipFlags = SKIP_HIDDEN | SKIP_BACKFACE
|
||||
# Skip camera (and its children), unless control key is pressed
|
||||
skipFlags |= SKIP_CAMERA * (1 - base.getControl())
|
||||
nodePath, hitPt, hitPtDist = direct.iRay.pickGeom(
|
||||
skipFlags = skipFlags)
|
||||
self.computeCOA(nodePath, hitPt, hitPtDist)
|
||||
self.computeCOA(direct.iRay.pickGeom(skipFlags = skipFlags))
|
||||
# Record reference point
|
||||
self.coaMarkerRef.iPosHprScale(base.cam)
|
||||
# Record entries
|
||||
@ -307,7 +305,7 @@ class DirectCameraControl(PandaObject):
|
||||
self.cqEntries = self.cqEntries[:-1]
|
||||
self.pickNextCOA()
|
||||
|
||||
def computeCOA(self, nodePath, hitPt, hitPtDist):
|
||||
def computeCOA(self, entry):
|
||||
coa = Point3(0)
|
||||
dr = direct.drList.getCurrentDr()
|
||||
if self.fLockCOA:
|
||||
@ -316,9 +314,11 @@ class DirectCameraControl(PandaObject):
|
||||
coa.assign(self.coaMarker.getPos(direct.camera))
|
||||
# Reset hit point count
|
||||
self.nullHitPointCount = 0
|
||||
elif nodePath:
|
||||
elif entry:
|
||||
# Got a hit point (hit point is in camera coordinates)
|
||||
# Set center of action
|
||||
hitPt = entry.getFromIntersectionPoint()
|
||||
hitPtDist = Vec3(hitPt).length()
|
||||
coa.assign(hitPt)
|
||||
# Handle case of bad coa point (too close or too far)
|
||||
if ((hitPtDist < (1.1 * dr.near)) or
|
||||
|
@ -40,14 +40,14 @@ class DirectManipulationControl(PandaObject):
|
||||
# Start out in select mode
|
||||
self.mode = 'select'
|
||||
# Check for a widget hit point
|
||||
nodePath, hitPt, hitPtDist = direct.iRay.pickWidget()
|
||||
entry = direct.iRay.pickWidget()
|
||||
# Did we hit a widget?
|
||||
if nodePath:
|
||||
if entry:
|
||||
# Yes!
|
||||
self.hitPt.assign(hitPt)
|
||||
self.hitPtDist = hitPtDist
|
||||
self.hitPt.assign(entry.getFromIntersectionPoint())
|
||||
self.hitPtDist = Vec3(self.hitPt).length()
|
||||
# Constraint determined by nodes name
|
||||
self.constraint = nodePath.getName()
|
||||
self.constraint = entry.getIntoNodePath().getName()
|
||||
else:
|
||||
# Nope, off the widget, no constraint
|
||||
self.constraint = None
|
||||
@ -90,14 +90,13 @@ class DirectManipulationControl(PandaObject):
|
||||
skipFlags = SKIP_HIDDEN | SKIP_BACKFACE
|
||||
# Skip camera (and its children), unless control key is pressed
|
||||
skipFlags |= SKIP_CAMERA * (1 - base.getControl())
|
||||
nodePath, hitPt, hitPtDist = direct.iRay.pickGeom(
|
||||
skipFlags = skipFlags)
|
||||
if nodePath:
|
||||
entry = direct.iRay.pickGeom(skipFlags = skipFlags)
|
||||
if entry:
|
||||
# Record hit point information
|
||||
self.hitPt.assign(hitPt)
|
||||
self.hitPtDist = hitPtDist
|
||||
self.hitPt.assign(entry.getFromIntersectionPoint())
|
||||
self.hitPtDist = Vec3(self.hitPt).length()
|
||||
# Select it
|
||||
direct.select(nodePath, direct.fShift)
|
||||
direct.select(entry.getIntoNodePath(), direct.fShift)
|
||||
else:
|
||||
direct.deselectAll()
|
||||
else:
|
||||
@ -484,16 +483,17 @@ class DirectManipulationControl(PandaObject):
|
||||
def plantSelectedNodePath(self):
|
||||
""" Move selected object to intersection point of cursor on scene """
|
||||
# Check for intersection
|
||||
nodePath, hitPt, hitPtDist = direct.iRay.pickGeom(
|
||||
entry = direct.iRay.pickGeom(
|
||||
skipFlags = SKIP_HIDDEN | SKIP_BACKFACE | SKIP_CAMERA)
|
||||
# MRM: Need to handle moving COA
|
||||
if (nodePath != None) and (direct.selected.last != None):
|
||||
if (entry != None) and (direct.selected.last != None):
|
||||
# Record undo point
|
||||
direct.pushUndo(direct.selected)
|
||||
# Record wrt matrix
|
||||
direct.selected.getWrtAll()
|
||||
# Move selected
|
||||
direct.widget.setPos(direct.camera, hitPt)
|
||||
direct.widget.setPos(
|
||||
direct.camera,entry.getFromIntersectionPoint())
|
||||
# Move all the selected objects with widget
|
||||
# Move the objects with the widget
|
||||
direct.selected.moveWrtWidgetAll()
|
||||
|
@ -379,13 +379,16 @@ class DirectBoundingBox:
|
||||
|
||||
|
||||
class SelectionQueue(CollisionHandlerQueue):
|
||||
def __init__(self, parent):
|
||||
def __init__(self, fromNP = render):
|
||||
# Initialize the superclass
|
||||
CollisionHandlerQueue.__init__(self)
|
||||
# Current entry in collision queue
|
||||
# Current index and entry in collision queue
|
||||
self.index = -1
|
||||
# Create a collision node path attached to the given parent
|
||||
self.collisionNodePath = parent.attachNewNode( CollisionNode("ray") )
|
||||
self.entry = None
|
||||
self.skipFlags = SKIP_NONE
|
||||
# Create a collision node path attached to the given NP
|
||||
self.collisionNodePath = NodePath(CollisionNode("collisionNP"))
|
||||
self.setFromNP(fromNP)
|
||||
# Don't pay the penalty of drawing this collision ray
|
||||
self.collisionNodePath.hide()
|
||||
self.collisionNode = self.collisionNodePath.node()
|
||||
@ -399,6 +402,10 @@ class SelectionQueue(CollisionHandlerQueue):
|
||||
self.unpickable = UNPICKABLE
|
||||
# Derived class must add Collider to complete initialization
|
||||
|
||||
def setFromNP(self, fromNP):
|
||||
# Update fromNP
|
||||
self.collisionNodePath.reparentTo(fromNP)
|
||||
|
||||
def addCollider(self, collider):
|
||||
# Inherited class must call this function to specify collider object
|
||||
# Record collision object
|
||||
@ -426,12 +433,18 @@ class SelectionQueue(CollisionHandlerQueue):
|
||||
if item in self.unpickable:
|
||||
self.unpickable.remove(item)
|
||||
|
||||
def getCurrentEntry(self):
|
||||
if self.index < 0:
|
||||
return None
|
||||
def setCurrentIndex(self, index):
|
||||
if (index < 0) or (index >= self.getNumEntries()):
|
||||
self.index = -1
|
||||
else:
|
||||
return self.getEntry(self.index)
|
||||
|
||||
self.index = index
|
||||
|
||||
def setCurrentEntry(self, entry):
|
||||
self.entry = entry
|
||||
|
||||
def getCurrentEntry(self):
|
||||
return self.entry
|
||||
|
||||
def isEntryBackfacing(self, entry):
|
||||
# If dot product of collision point surface normal and
|
||||
# ray from camera to collision point is positive, we are
|
||||
@ -440,10 +453,39 @@ class SelectionQueue(CollisionHandlerQueue):
|
||||
v.normalize()
|
||||
return v.dot(entry.getFromSurfaceNormal()) >= 0
|
||||
|
||||
class NewSelectionRay(SelectionQueue):
|
||||
def __init__(self,parent):
|
||||
def findCollisionEntry(self, skipFlags = SKIP_NONE, startIndex = 0 ):
|
||||
# Init self.index and self.entry
|
||||
self.setCurrentIndex(-1)
|
||||
self.setCurrentEntry(None)
|
||||
# Pick out the closest object that isn't a widget
|
||||
for i in range(startIndex,self.getNumEntries()):
|
||||
entry = self.getEntry(i)
|
||||
nodePath = entry.getIntoNodePath()
|
||||
if (skipFlags & SKIP_HIDDEN) and nodePath.isHidden():
|
||||
# Skip if hidden node
|
||||
pass
|
||||
elif (skipFlags & SKIP_BACKFACE) and self.isEntryBackfacing(entry):
|
||||
# Skip, if backfacing poly
|
||||
pass
|
||||
elif ((skipFlags & SKIP_CAMERA) and
|
||||
(camera in nodePath.getAncestry())):
|
||||
# Skip if parented to a camera.
|
||||
pass
|
||||
# Can pick unpickable, use the first visible node
|
||||
elif ((skipFlags & SKIP_UNPICKABLE) and
|
||||
(nodePath.getName() in self.unpickable)):
|
||||
# Skip if in unpickable list
|
||||
pass
|
||||
else:
|
||||
self.setCurrentIndex(i)
|
||||
self.setCurrentEntry(entry)
|
||||
break
|
||||
return self.getCurrentEntry()
|
||||
|
||||
class SelectionRay(SelectionQueue):
|
||||
def __init__(self, fromNP = render):
|
||||
# Initialize the superclass
|
||||
SelectionQueue.__init__(self, parent)
|
||||
SelectionQueue.__init__(self, fromNP)
|
||||
self.addCollider(CollisionRay())
|
||||
|
||||
def pick(self, targetNodePath):
|
||||
@ -485,37 +527,35 @@ class NewSelectionRay(SelectionQueue):
|
||||
# Determine collision entry
|
||||
return self.findCollisionEntry(skipFlags)
|
||||
|
||||
def findCollisionEntry(self, skipFlags = SKIP_NONE ):
|
||||
# Init self.index
|
||||
self.index = -1
|
||||
# Pick out the closest object that isn't a widget
|
||||
for i in range(0,self.getNumEntries()):
|
||||
entry = self.getEntry(i)
|
||||
nodePath = entry.getIntoNodePath()
|
||||
if (skipFlags & SKIP_HIDDEN) and nodePath.isHidden():
|
||||
# Skip if hidden node
|
||||
pass
|
||||
elif (skipFlags & SKIP_BACKFACE) and self.isEntryBackfacing(entry):
|
||||
# Skip, if backfacing poly
|
||||
pass
|
||||
elif ((skipFlags & SKIP_CAMERA) and
|
||||
(camera in nodePath.getAncestry())):
|
||||
# Skip if parented to a camera.
|
||||
pass
|
||||
# Can pick unpickable, use the first visible node
|
||||
elif ((skipFlags & SKIP_UNPICKABLE) and
|
||||
(nodePath.getName() in self.unpickable)):
|
||||
# Skip if in unpickable list
|
||||
pass
|
||||
else:
|
||||
self.index = i
|
||||
break
|
||||
# Did we hit an object?
|
||||
if(self.index >= 0):
|
||||
# Yes! Find hit point in parent's space
|
||||
hitPt = entry.getFromIntersectionPoint()
|
||||
hitPtDist = Vec3(hitPt).length()
|
||||
return (nodePath, hitPt, hitPtDist)
|
||||
else:
|
||||
return (None, ZERO_POINT, 0)
|
||||
|
||||
class SelectionSegment(SelectionQueue):
|
||||
# Like a selection ray but with two endpoints instead of an endpoint
|
||||
# and a direction
|
||||
def __init__(self, fromNP = render, numSegments = 1):
|
||||
# Initialize the superclass
|
||||
SelectionQueue.__init__(self, fromNP)
|
||||
self.colliders = []
|
||||
self.numColliders = 0
|
||||
for i in range(numSegments):
|
||||
self.addCollider(CollisionSegment())
|
||||
|
||||
def addCollider(self, collider):
|
||||
# Record new collision object
|
||||
self.colliders.append(collider)
|
||||
# Add the collider to the collision Node
|
||||
self.collisionNode.addSolid( collider )
|
||||
self.numColliders += 1
|
||||
|
||||
def pickGeom(self, targetNodePath = render, endPointList = [],
|
||||
skipFlags = SKIP_HIDDEN | SKIP_CAMERA ):
|
||||
self.collideWithGeom()
|
||||
for i in range(min(len(endPointList), self.numColliders)):
|
||||
pointA, pointB = endPointList[i]
|
||||
collider = self.colliders[i]
|
||||
collider.setPointA( pointA )
|
||||
collider.setPointB( pointB )
|
||||
self.ct.traverse( targetNodePath )
|
||||
# self.sortEntries()
|
||||
# Determine collision entry
|
||||
return self.findCollisionEntry(skipFlags)
|
||||
|
||||
|
@ -784,7 +784,7 @@ class DisplayRegionContext(PandaObject):
|
||||
DisplayRegionContext.regionCount += 1
|
||||
self.camLens.setChangeEvent(changeEvent)
|
||||
self.accept(changeEvent, self.camUpdate)
|
||||
self.iRay = NewSelectionRay(self.cam)
|
||||
self.iRay = SelectionRay(self.cam)
|
||||
self.nearVec = Vec3(0)
|
||||
self.mouseX = 0.0
|
||||
self.mouseY = 0.0
|
||||
|
@ -1675,8 +1675,9 @@ class MopathRecorder(AppShell, PandaObject):
|
||||
|
||||
def followTerrain(self, height = 1.0):
|
||||
self.iRay.rayCollisionNodePath.reparentTo(self.nodePath)
|
||||
nodePath, hitPt, hitPtDist = self.iRay.pickGeom3D()
|
||||
if nodePath:
|
||||
entry = self.iRay.pickGeom3D()
|
||||
if entry:
|
||||
hitPtDist = Vec3(entry.getFromIntersectionPoint()).length()
|
||||
self.nodePath.setZ(self.nodePath, height - hitPtDist)
|
||||
self.iRay.rayCollisionNodePath.reparentTo(self.recorderNodePath)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user