mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 19:08:55 -04:00
*** empty log message ***
This commit is contained in:
parent
21933936d5
commit
11cdb8a6be
@ -55,7 +55,10 @@ class DirectJoybox(PandaObject):
|
|||||||
self.refCS = direct.cameraControl.coaMarker
|
self.refCS = direct.cameraControl.coaMarker
|
||||||
self.tempCS = direct.group.attachNewNode('JoyboxTempCS')
|
self.tempCS = direct.group.attachNewNode('JoyboxTempCS')
|
||||||
# Text object to display current mode
|
# Text object to display current mode
|
||||||
self.readout = OnscreenText.OnscreenText( pos = (-0.9, 0.95) )
|
self.readout = OnscreenText.OnscreenText(
|
||||||
|
pos = (-0.9, 0.95),
|
||||||
|
font = direct.font,
|
||||||
|
mayChange = 1)
|
||||||
# List of functions to cycle through
|
# List of functions to cycle through
|
||||||
self.modeList = [self.joeMode, self.driveMode, self.orbitMode]
|
self.modeList = [self.joeMode, self.driveMode, self.orbitMode]
|
||||||
# Pick initial mode
|
# Pick initial mode
|
||||||
|
@ -8,10 +8,11 @@ Y_AXIS = Vec3(0,1,0)
|
|||||||
class DirectCameraControl(PandaObject):
|
class DirectCameraControl(PandaObject):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# Create the grid
|
# Create the grid
|
||||||
|
self.startT = 0.0
|
||||||
|
self.startF = 0
|
||||||
self.orthoViewRoll = 0.0
|
self.orthoViewRoll = 0.0
|
||||||
self.lastView = 0
|
self.lastView = 0
|
||||||
self.coa = Point3(0,100,0)
|
self.coa = Point3(0,100,0)
|
||||||
self.coaDist = 100
|
|
||||||
self.coaMarker = loader.loadModel('models/misc/sphere')
|
self.coaMarker = loader.loadModel('models/misc/sphere')
|
||||||
self.coaMarker.setName('DirectCameraCOAMarker')
|
self.coaMarker.setName('DirectCameraCOAMarker')
|
||||||
self.coaMarker.setTransparency(1)
|
self.coaMarker.setTransparency(1)
|
||||||
@ -19,7 +20,10 @@ class DirectCameraControl(PandaObject):
|
|||||||
self.coaMarker.setPos(0,100,0)
|
self.coaMarker.setPos(0,100,0)
|
||||||
useDirectRenderStyle(self.coaMarker)
|
useDirectRenderStyle(self.coaMarker)
|
||||||
self.coaMarkerPos = Point3(0)
|
self.coaMarkerPos = Point3(0)
|
||||||
self.fUpdateCOA = 1
|
self.fLockCOA = 1
|
||||||
|
self.nullHitPtCount = 0
|
||||||
|
self.cqEntries = []
|
||||||
|
self.coaMarkerRef = direct.group.attachNewNode('coaMarkerRef')
|
||||||
self.camManipRef = direct.group.attachNewNode('camManipRef')
|
self.camManipRef = direct.group.attachNewNode('camManipRef')
|
||||||
t = CAM_MOVE_DURATION
|
t = CAM_MOVE_DURATION
|
||||||
self.actionEvents = [
|
self.actionEvents = [
|
||||||
@ -64,13 +68,9 @@ class DirectCameraControl(PandaObject):
|
|||||||
# MOUSE IS IN CENTRAL REGION
|
# MOUSE IS IN CENTRAL REGION
|
||||||
# Hide the marker for this kind of motion
|
# Hide the marker for this kind of motion
|
||||||
self.coaMarker.hide()
|
self.coaMarker.hide()
|
||||||
# Check for a hit point based on
|
# Record time of start of mouse interaction
|
||||||
# current mouse position
|
self.startT= globalClock.getFrameTime()
|
||||||
# Allow intersection with unpickable objects
|
self.startF = globalClock.getFrameCount()
|
||||||
# And then spawn task to determine mouse mode
|
|
||||||
node, hitPt, hitPtDist = direct.iRay.pickGeom(
|
|
||||||
fIntersectUnpickable = 1)
|
|
||||||
self.computeCOA(node, hitPt, hitPtDist)
|
|
||||||
# Start manipulation
|
# Start manipulation
|
||||||
self.spawnXZTranslateOrHPanYZoom()
|
self.spawnXZTranslateOrHPanYZoom()
|
||||||
# END MOUSE IN CENTRAL REGION
|
# END MOUSE IN CENTRAL REGION
|
||||||
@ -85,6 +85,24 @@ class DirectCameraControl(PandaObject):
|
|||||||
|
|
||||||
def mouseFlyStop(self):
|
def mouseFlyStop(self):
|
||||||
taskMgr.removeTasksNamed('manipulateCamera')
|
taskMgr.removeTasksNamed('manipulateCamera')
|
||||||
|
stopT = globalClock.getFrameTime()
|
||||||
|
deltaT = stopT - self.startT
|
||||||
|
stopF = globalClock.getFrameCount()
|
||||||
|
deltaF = stopF - self.startF
|
||||||
|
if (deltaT <= 0.25) or (deltaF <= 1):
|
||||||
|
# Check for a hit point based on
|
||||||
|
# current mouse position
|
||||||
|
# Allow intersection with unpickable objects
|
||||||
|
# And then spawn task to determine mouse mode
|
||||||
|
node, hitPt, hitPtDist = direct.iRay.pickGeom(
|
||||||
|
fIntersectUnpickable = 1, fIgnoreCamera = 1)
|
||||||
|
self.computeCOA(node, hitPt, hitPtDist)
|
||||||
|
# Record reference point
|
||||||
|
self.coaMarkerRef.iPosHprScale(direct.iRay.collisionRef)
|
||||||
|
# Record entries
|
||||||
|
self.cqEntries = []
|
||||||
|
for i in range(direct.iRay.cq.getNumEntries()):
|
||||||
|
self.cqEntries.append(direct.iRay.cq.getEntry(i))
|
||||||
# Show the marker
|
# Show the marker
|
||||||
self.coaMarker.show()
|
self.coaMarker.show()
|
||||||
# Resize it
|
# Resize it
|
||||||
@ -96,7 +114,8 @@ class DirectCameraControl(PandaObject):
|
|||||||
# Spawn the new task
|
# Spawn the new task
|
||||||
t = Task.Task(self.XZTranslateOrHPanYZoomTask)
|
t = Task.Task(self.XZTranslateOrHPanYZoomTask)
|
||||||
# For HPanYZoom
|
# For HPanYZoom
|
||||||
t.zoomSF = Vec3(self.coa).length()
|
coaDist = Vec3(self.coaMarker.getPos(direct.camera)).length()
|
||||||
|
t.zoomSF = (coaDist / direct.dr.near)
|
||||||
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
|
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
|
||||||
|
|
||||||
def spawnXZTranslateOrHPPan(self):
|
def spawnXZTranslateOrHPPan(self):
|
||||||
@ -117,7 +136,8 @@ class DirectCameraControl(PandaObject):
|
|||||||
taskMgr.removeTasksNamed('manipulateCamera')
|
taskMgr.removeTasksNamed('manipulateCamera')
|
||||||
# Spawn new task
|
# Spawn new task
|
||||||
t = Task.Task(self.HPanYZoomTask)
|
t = Task.Task(self.HPanYZoomTask)
|
||||||
t.zoomSF = Vec3(self.coa).length()
|
coaDist = Vec3(self.coaMarker.getPos(direct.camera)).length()
|
||||||
|
t.zoomSF = (coaDist / direct.dr.near)
|
||||||
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
|
taskMgr.spawnTaskNamed(t, 'manipulateCamera')
|
||||||
|
|
||||||
def spawnHPPan(self):
|
def spawnHPPan(self):
|
||||||
@ -155,15 +175,17 @@ class DirectCameraControl(PandaObject):
|
|||||||
|
|
||||||
def HPanYZoomTask(self,state):
|
def HPanYZoomTask(self,state):
|
||||||
if direct.fControl:
|
if direct.fControl:
|
||||||
moveDir = Vec3(Y_AXIS)
|
|
||||||
else:
|
|
||||||
moveDir = Vec3(self.coaMarker.getPos(direct.camera))
|
moveDir = Vec3(self.coaMarker.getPos(direct.camera))
|
||||||
# If marker is behind camera invert vector
|
# If marker is behind camera invert vector
|
||||||
if moveDir[1] < 0.0:
|
if moveDir[1] < 0.0:
|
||||||
moveDir.assign(moveDir * -1)
|
moveDir.assign(moveDir * -1)
|
||||||
moveDir.normalize()
|
moveDir.normalize()
|
||||||
|
else:
|
||||||
|
moveDir = Vec3(Y_AXIS)
|
||||||
moveDir.assign(moveDir * (-2.0 * direct.dr.mouseDeltaY *
|
moveDir.assign(moveDir * (-2.0 * direct.dr.mouseDeltaY *
|
||||||
state.zoomSF))
|
state.zoomSF))
|
||||||
|
if direct.dr.mouseDeltaY > 0.0:
|
||||||
|
moveDir.setY(moveDir[1] * 1.0)
|
||||||
direct.camera.setPosHpr(direct.camera,
|
direct.camera.setPosHpr(direct.camera,
|
||||||
moveDir[0],
|
moveDir[0],
|
||||||
moveDir[1],
|
moveDir[1],
|
||||||
@ -247,54 +269,85 @@ class DirectCameraControl(PandaObject):
|
|||||||
return Task.cont
|
return Task.cont
|
||||||
|
|
||||||
def lockCOA(self):
|
def lockCOA(self):
|
||||||
self.fUpdateCOA = 0
|
self.fLockCOA = 1
|
||||||
|
direct.message('COA Lock On')
|
||||||
|
|
||||||
def unlockCOA(self):
|
def unlockCOA(self):
|
||||||
self.fUpdateCOA = 1
|
self.fLockCOA = 0
|
||||||
|
direct.message('COA Lock Off')
|
||||||
|
|
||||||
def toggleCOALock(self):
|
def toggleCOALock(self):
|
||||||
self.fUpdateCOA = 1 - self.fUpdateCOA
|
self.fLockCOA = 1 - self.fLockCOA
|
||||||
|
if self.fLockCOA:
|
||||||
|
direct.message('COA Lock On')
|
||||||
|
else:
|
||||||
|
direct.message('COA Lock Off')
|
||||||
|
|
||||||
def pickNextCOA(self):
|
def pickNextCOA(self):
|
||||||
""" Cycle through collision handler entries """
|
""" Cycle through collision handler entries """
|
||||||
node, hitPt, hitPtDist = direct.iRay.pickNext()
|
if self.cqEntries:
|
||||||
self.computeCOA(node, hitPt, hitPtDist)
|
# Get next entry and rotate entries
|
||||||
|
entry = self.cqEntries[0]
|
||||||
|
self.cqEntries = self.cqEntries[1:] + self.cqEntries[:1]
|
||||||
|
# Filter out object's under camera
|
||||||
|
node = entry.getIntoNode()
|
||||||
|
nodePath = render.findPathDownTo(node)
|
||||||
|
if camera not in nodePath.getAncestry():
|
||||||
|
# Compute hit point
|
||||||
|
hitPt = direct.iRay.parentToHitPt(entry)
|
||||||
|
# Move coa marker to new point
|
||||||
|
self.updateCoa(hitPt, ref = self.coaMarkerRef)
|
||||||
|
else:
|
||||||
|
# Remove offending entry
|
||||||
|
self.cqEntries = self.cqEntries[:-1]
|
||||||
|
self.pickNextCOA()
|
||||||
|
|
||||||
def computeCOA(self, node, hitPt, hitPtDist):
|
def computeCOA(self, node, hitPt, hitPtDist):
|
||||||
coa = Point3(0)
|
coa = Point3(0)
|
||||||
if self.fUpdateCOA and node:
|
if self.fLockCOA:
|
||||||
# Set center of action
|
# COA is locked, use existing point
|
||||||
coa.assign(hitPt)
|
|
||||||
coaDist = hitPtDist
|
|
||||||
# Handle case of bad coa point (too close or too far)
|
|
||||||
if ((coaDist < (1.1 * direct.dr.near)) or
|
|
||||||
(coaDist > direct.dr.far)):
|
|
||||||
# Just use existing point
|
|
||||||
coa.assign(self.coaMarker.getPos(direct.camera))
|
|
||||||
coaDist = Vec3(coa - ZERO_POINT).length()
|
|
||||||
if coaDist < (1.1 * direct.dr.near):
|
|
||||||
coa.set(0,100,0)
|
|
||||||
coaDist = 100
|
|
||||||
else:
|
|
||||||
# If no intersection point or COA is locked:
|
|
||||||
# Use existing point
|
# Use existing point
|
||||||
coa.assign(self.coaMarker.getPos(direct.camera))
|
coa.assign(self.coaMarker.getPos(direct.camera))
|
||||||
|
# Reset hit point count
|
||||||
|
self.nullHitPointCount = 0
|
||||||
|
elif node:
|
||||||
|
# Got a hit point (hit point is in camera coordinates)
|
||||||
|
# Set center of action
|
||||||
|
coa.assign(hitPt)
|
||||||
|
# Handle case of bad coa point (too close or too far)
|
||||||
|
if ((hitPtDist < (1.1 * direct.dr.near)) or
|
||||||
|
(hitPtDist > direct.dr.far)):
|
||||||
|
# Just use existing point
|
||||||
|
coa.assign(self.coaMarker.getPos(direct.camera))
|
||||||
|
# Reset hit point count
|
||||||
|
self.nullHitPointCount = 0
|
||||||
|
else:
|
||||||
|
# Increment null hit point count
|
||||||
|
self.nullHitPointCount = (self.nullHitPointCount + 1) % 7
|
||||||
|
# No COA lock and no intersection point
|
||||||
|
# Use a point out in front of camera
|
||||||
|
# Distance to point increases on multiple null hit points
|
||||||
|
# MRM: Would be nice to be able to control this
|
||||||
|
# At least display it
|
||||||
|
dist = pow(10.0, self.nullHitPointCount)
|
||||||
|
direct.message('COA Distance: ' + `dist`)
|
||||||
|
coa.set(0,dist,0)
|
||||||
|
# Compute COA Dist
|
||||||
coaDist = Vec3(coa - ZERO_POINT).length()
|
coaDist = Vec3(coa - ZERO_POINT).length()
|
||||||
# Check again its not to close
|
|
||||||
if coaDist < (1.1 * direct.dr.near):
|
if coaDist < (1.1 * direct.dr.near):
|
||||||
coa.set(0,100,0)
|
coa.set(0,100,0)
|
||||||
coaDist = 100
|
coaDist = 100
|
||||||
# Update coa and marker
|
# Update coa and marker
|
||||||
self.updateCoa(coa, coaDist)
|
self.updateCoa(coa, coaDist = coaDist)
|
||||||
|
|
||||||
def updateCoa(self, cam2point, coaDist = None):
|
def updateCoa(self, ref2point, coaDist = None, ref = None):
|
||||||
self.coa.set(cam2point[0], cam2point[1], cam2point[2])
|
self.coa.set(ref2point[0], ref2point[1], ref2point[2])
|
||||||
if coaDist:
|
if not coaDist:
|
||||||
self.coaDist = coaDist
|
coaDist = Vec3(self.coa - ZERO_POINT).length()
|
||||||
else:
|
|
||||||
self.coaDist = Vec3(self.coa - ZERO_POINT).length()
|
|
||||||
# Place the marker in render space
|
# Place the marker in render space
|
||||||
self.coaMarker.setPos(direct.camera,self.coa)
|
if ref == None:
|
||||||
|
ref = base.cam
|
||||||
|
self.coaMarker.setPos(ref, self.coa)
|
||||||
# Resize it
|
# Resize it
|
||||||
self.updateCoaMarkerSize(coaDist)
|
self.updateCoaMarkerSize(coaDist)
|
||||||
# Record marker pos in render space
|
# Record marker pos in render space
|
||||||
|
@ -231,7 +231,7 @@ class DirectManipulationControl(PandaObject):
|
|||||||
else:
|
else:
|
||||||
# Mouse started in central region, xlate
|
# Mouse started in central region, xlate
|
||||||
# Mode depends on shift key
|
# Mode depends on shift key
|
||||||
if direct.fShift:
|
if direct.fShift or direct.fControl:
|
||||||
self.xlateCamXY(state)
|
self.xlateCamXY(state)
|
||||||
else:
|
else:
|
||||||
self.xlateCamXZ(state)
|
self.xlateCamXZ(state)
|
||||||
@ -367,7 +367,11 @@ class DirectManipulationControl(PandaObject):
|
|||||||
|
|
||||||
def xlateCamXY(self, state):
|
def xlateCamXY(self, state):
|
||||||
"""Constrained 2D motion perpendicular to camera's image plane
|
"""Constrained 2D motion perpendicular to camera's image plane
|
||||||
This moves the object in the camera's XY plane"""
|
This moves the object in the camera's XY plane if shift is held
|
||||||
|
Moves object toward camera if control is held
|
||||||
|
"""
|
||||||
|
# Reset scaling init flag
|
||||||
|
self.fScaleInit = 1
|
||||||
# Now, where is the widget relative to current camera view
|
# Now, where is the widget relative to current camera view
|
||||||
vWidget2Camera = direct.widget.getPos(direct.camera)
|
vWidget2Camera = direct.widget.getPos(direct.camera)
|
||||||
# If this is first time around, record initial y distance
|
# If this is first time around, record initial y distance
|
||||||
@ -378,15 +382,26 @@ class DirectManipulationControl(PandaObject):
|
|||||||
# Get widget's current xy coords in screen space
|
# Get widget's current xy coords in screen space
|
||||||
coaCenter = getNearProjectionPoint(direct.widget)
|
coaCenter = getNearProjectionPoint(direct.widget)
|
||||||
self.deltaNearX = coaCenter[0] - direct.dr.nearVec[0]
|
self.deltaNearX = coaCenter[0] - direct.dr.nearVec[0]
|
||||||
# Reset scaling init flag
|
# Which way do we move the object?
|
||||||
self.fScaleInit = 1
|
if direct.fControl:
|
||||||
|
moveDir = Vec3(vWidget2Camera)
|
||||||
|
# If widget is behind camera invert vector
|
||||||
|
if moveDir[1] < 0.0:
|
||||||
|
moveDir.assign(moveDir * -1)
|
||||||
|
moveDir.normalize()
|
||||||
|
else:
|
||||||
|
moveDir = Vec3(Y_AXIS)
|
||||||
# Move selected objects
|
# Move selected objects
|
||||||
dr = direct.dr
|
dr = direct.dr
|
||||||
# Move object in y axis based on mouse motion
|
# Scale move dir
|
||||||
newY = vWidget2Camera[1] + self.xlateSF * dr.mouseDeltaY
|
moveDir.assign(moveDir * (2.0 * dr.mouseDeltaY * self.xlateSF))
|
||||||
# Put object at same relative point to mouse in X
|
# Add it to current widget offset
|
||||||
newX = (direct.dr.nearVec[0] + self.deltaNearX) * (newY/dr.near)
|
vWidget2Camera += moveDir
|
||||||
direct.widget.setPos(direct.camera, newX, newY, vWidget2Camera[2])
|
# The object, however, stays at the same relative point to mouse in X
|
||||||
|
vWidget2Camera.setX((dr.nearVec[0] + self.deltaNearX) *
|
||||||
|
(vWidget2Camera[1]/dr.near))
|
||||||
|
# Move widget
|
||||||
|
direct.widget.setPos(direct.camera, vWidget2Camera)
|
||||||
|
|
||||||
def rotate2D(self, state):
|
def rotate2D(self, state):
|
||||||
""" Virtual trackball rotation of widget """
|
""" Virtual trackball rotation of widget """
|
||||||
|
@ -403,6 +403,8 @@ class SelectionRay:
|
|||||||
self.ct = CollisionTraverser( RenderRelation.getClassType() )
|
self.ct = CollisionTraverser( RenderRelation.getClassType() )
|
||||||
# Let the traverser know about the queue and the collision node
|
# Let the traverser know about the queue and the collision node
|
||||||
self.ct.addCollider(self.rayCollisionNode, self.cq )
|
self.ct.addCollider(self.rayCollisionNode, self.cq )
|
||||||
|
# Reference node path (for picking next)
|
||||||
|
self.collisionRef = direct.group.attachNewNode('collisionRef')
|
||||||
# List of objects that can't be selected
|
# List of objects that can't be selected
|
||||||
self.unpickable = UNPICKABLE
|
self.unpickable = UNPICKABLE
|
||||||
|
|
||||||
@ -414,7 +416,8 @@ class SelectionRay:
|
|||||||
if item in self.unpickable:
|
if item in self.unpickable:
|
||||||
self.unpickable.remove(item)
|
self.unpickable.remove(item)
|
||||||
|
|
||||||
def pickGeom(self, targetNodePath = render, fIntersectUnpickable = 0):
|
def pickGeom(self, targetNodePath = render, fIntersectUnpickable = 0,
|
||||||
|
fIgnoreCamera = 0):
|
||||||
self.collideWithGeom()
|
self.collideWithGeom()
|
||||||
self.pick(targetNodePath,
|
self.pick(targetNodePath,
|
||||||
direct.dr.mouseX,
|
direct.dr.mouseX,
|
||||||
@ -425,9 +428,13 @@ class SelectionRay:
|
|||||||
for i in range(0,self.numEntries):
|
for i in range(0,self.numEntries):
|
||||||
entry = self.cq.getEntry(i)
|
entry = self.cq.getEntry(i)
|
||||||
node = entry.getIntoNode()
|
node = entry.getIntoNode()
|
||||||
|
nodePath = render.findPathDownTo(node)
|
||||||
# Don't pick hidden nodes
|
# Don't pick hidden nodes
|
||||||
if node.isHidden():
|
if node.isHidden():
|
||||||
pass
|
pass
|
||||||
|
elif fIgnoreCamera and (camera in nodePath.getAncestry()):
|
||||||
|
# This avoids things parented to a camera. Good idea?
|
||||||
|
pass
|
||||||
# Can pick unpickable, use the first visible node
|
# Can pick unpickable, use the first visible node
|
||||||
elif fIntersectUnpickable:
|
elif fIntersectUnpickable:
|
||||||
self.cqIndex = i
|
self.cqIndex = i
|
||||||
@ -448,7 +455,8 @@ class SelectionRay:
|
|||||||
if(self.cqIndex >= 0):
|
if(self.cqIndex >= 0):
|
||||||
# Yes!
|
# Yes!
|
||||||
# Find hit point in parent's space
|
# Find hit point in parent's space
|
||||||
hitPt = self.parentToHitPt(self.cqIndex)
|
entry = self.cq.getEntry(self.cqIndex)
|
||||||
|
hitPt = self.parentToHitPt(entry)
|
||||||
hitPtDist = Vec3(hitPt - ZERO_POINT).length()
|
hitPtDist = Vec3(hitPt - ZERO_POINT).length()
|
||||||
return (node, hitPt, hitPtDist)
|
return (node, hitPt, hitPtDist)
|
||||||
else:
|
else:
|
||||||
@ -465,7 +473,8 @@ class SelectionRay:
|
|||||||
# Entry 0 is the closest hit point if multiple hits
|
# Entry 0 is the closest hit point if multiple hits
|
||||||
minPt = 0
|
minPt = 0
|
||||||
# Find hit point in parent's space
|
# Find hit point in parent's space
|
||||||
hitPt = self.parentToHitPt(minPt)
|
entry = self.cq.getEntry(minPt)
|
||||||
|
hitPt = self.parentToHitPt(entry)
|
||||||
hitPtDist = Vec3(hitPt).length()
|
hitPtDist = Vec3(hitPt).length()
|
||||||
# Get the associated collision queue object
|
# Get the associated collision queue object
|
||||||
entry = self.cq.getEntry(minPt)
|
entry = self.cq.getEntry(minPt)
|
||||||
@ -483,15 +492,18 @@ class SelectionRay:
|
|||||||
self.ct.traverse( targetNodePath.node() )
|
self.ct.traverse( targetNodePath.node() )
|
||||||
self.numEntries = self.cq.getNumEntries()
|
self.numEntries = self.cq.getNumEntries()
|
||||||
self.cq.sortEntries()
|
self.cq.sortEntries()
|
||||||
|
# Record cam's current position (used for cycling through
|
||||||
|
# other hit points)
|
||||||
|
self.collisionRef.iPosHprScale(base.cam)
|
||||||
return self.numEntries
|
return self.numEntries
|
||||||
|
|
||||||
def pickNext(self):
|
def getHitPt(self, entry):
|
||||||
if self.cqIndex >= 0:
|
if self.cqIndex >= 0:
|
||||||
self.cqIndex = (self.cqIndex + 1) % self.numEntries
|
self.cqIndex = (self.cqIndex + 1) % self.numEntries
|
||||||
entry = self.cq.getEntry(self.cqIndex)
|
entry = self.cq.getEntry(self.cqIndex)
|
||||||
node = entry.getIntoNode()
|
node = entry.getIntoNode()
|
||||||
# Find hit point in parent's space
|
# Find hit point in parent's space
|
||||||
hitPt = self.parentToHitPt(self.cqIndex)
|
hitPt = self.parentToHitPt(entry)
|
||||||
hitPtDist = Vec3(hitPt - ZERO_POINT).length()
|
hitPtDist = Vec3(hitPt - ZERO_POINT).length()
|
||||||
return (node, hitPt, hitPtDist)
|
return (node, hitPt, hitPtDist)
|
||||||
else:
|
else:
|
||||||
@ -530,7 +542,8 @@ class SelectionRay:
|
|||||||
if(self.cqIndex >= 0):
|
if(self.cqIndex >= 0):
|
||||||
# Yes!
|
# Yes!
|
||||||
# Find hit point in parent's space
|
# Find hit point in parent's space
|
||||||
hitPt = self.parentToHitPt(self.cqIndex)
|
entry = self.cq.getEntry(self.cqIndex)
|
||||||
|
hitPt = self.parentToHitPt(entry)
|
||||||
hitPtDist = Vec3(hitPt - ZERO_POINT).length()
|
hitPtDist = Vec3(hitPt - ZERO_POINT).length()
|
||||||
return (node, hitPt, hitPtDist)
|
return (node, hitPt, hitPtDist)
|
||||||
else:
|
else:
|
||||||
@ -561,9 +574,8 @@ class SelectionRay:
|
|||||||
def objectToHitPt(self, index):
|
def objectToHitPt(self, index):
|
||||||
return self.cq.getEntry(index).getIntoIntersectionPoint()
|
return self.cq.getEntry(index).getIntoIntersectionPoint()
|
||||||
|
|
||||||
def parentToHitPt(self, index):
|
def parentToHitPt(self, entry):
|
||||||
# Get the specified entry
|
# Get hit point
|
||||||
entry = self.cq.getEntry(index)
|
|
||||||
hitPt = entry.getIntoIntersectionPoint()
|
hitPt = entry.getIntoIntersectionPoint()
|
||||||
# Convert point from object local space to parent's space
|
# Convert point from object local space to parent's space
|
||||||
return entry.getInvWrtSpace().xformPoint(hitPt)
|
return entry.getInvWrtSpace().xformPoint(hitPt)
|
||||||
|
@ -23,6 +23,10 @@ class DirectSession(PandaObject):
|
|||||||
# Establish a global pointer to the direct object early on
|
# Establish a global pointer to the direct object early on
|
||||||
# so dependant classes can access it in their code
|
# so dependant classes can access it in their code
|
||||||
__builtin__.direct = self
|
__builtin__.direct = self
|
||||||
|
# These come early since they are used later on
|
||||||
|
self.group = render.attachNewNode('DIRECT')
|
||||||
|
self.font = loader.loadFont("models/fonts/Comic")
|
||||||
|
|
||||||
self.fEnabled = 0
|
self.fEnabled = 0
|
||||||
self.drList = DisplayRegionList()
|
self.drList = DisplayRegionList()
|
||||||
self.iRayList = map(lambda x: x.iRay, self.drList)
|
self.iRayList = map(lambda x: x.iRay, self.drList)
|
||||||
@ -30,7 +34,6 @@ class DirectSession(PandaObject):
|
|||||||
self.camera = self.dr.camera
|
self.camera = self.dr.camera
|
||||||
self.iRay = self.dr.iRay
|
self.iRay = self.dr.iRay
|
||||||
|
|
||||||
self.group = render.attachNewNode('DIRECT')
|
|
||||||
self.cameraControl = DirectCameraControl()
|
self.cameraControl = DirectCameraControl()
|
||||||
self.manipulationControl = DirectManipulationControl()
|
self.manipulationControl = DirectManipulationControl()
|
||||||
self.useObjectHandles()
|
self.useObjectHandles()
|
||||||
@ -51,18 +54,28 @@ class DirectSession(PandaObject):
|
|||||||
|
|
||||||
self.selectedNPReadout = OnscreenText.OnscreenText(
|
self.selectedNPReadout = OnscreenText.OnscreenText(
|
||||||
pos = (-1.0, -0.9), bg=Vec4(1,1,1,1),
|
pos = (-1.0, -0.9), bg=Vec4(1,1,1,1),
|
||||||
scale = 0.05, align = TMALIGNLEFT)
|
scale = 0.05, align = TMALIGNLEFT,
|
||||||
|
mayChange = 1, font = self.font)
|
||||||
# Make sure readout is never lit or drawn in wireframe
|
# Make sure readout is never lit or drawn in wireframe
|
||||||
useDirectRenderStyle(self.selectedNPReadout)
|
useDirectRenderStyle(self.selectedNPReadout)
|
||||||
self.selectedNPReadout.reparentTo( hidden )
|
self.selectedNPReadout.reparentTo( hidden )
|
||||||
|
|
||||||
self.activeParentReadout = OnscreenText.OnscreenText(
|
self.activeParentReadout = OnscreenText.OnscreenText(
|
||||||
pos = (-1.0, -0.975), bg=Vec4(1,1,1,1),
|
pos = (-1.0, -0.975), bg=Vec4(1,1,1,1),
|
||||||
scale = 0.05, align = TMALIGNLEFT)
|
scale = 0.05, align = TMALIGNLEFT,
|
||||||
|
mayChange = 1, font = self.font)
|
||||||
# Make sure readout is never lit or drawn in wireframe
|
# Make sure readout is never lit or drawn in wireframe
|
||||||
useDirectRenderStyle(self.activeParentReadout)
|
useDirectRenderStyle(self.activeParentReadout)
|
||||||
self.activeParentReadout.reparentTo( hidden )
|
self.activeParentReadout.reparentTo( hidden )
|
||||||
|
|
||||||
|
self.directMessageReadout = OnscreenText.OnscreenText(
|
||||||
|
pos = (-1.0, 0.9), bg=Vec4(1,1,1,1),
|
||||||
|
scale = 0.05, align = TMALIGNLEFT,
|
||||||
|
mayChange = 1, font = self.font)
|
||||||
|
# Make sure readout is never lit or drawn in wireframe
|
||||||
|
useDirectRenderStyle(self.directMessageReadout)
|
||||||
|
self.directMessageReadout.reparentTo( hidden )
|
||||||
|
|
||||||
# Create a vrpn client vrpn-server or default
|
# Create a vrpn client vrpn-server or default
|
||||||
if base.config.GetBool('want-vrpn', 0):
|
if base.config.GetBool('want-vrpn', 0):
|
||||||
from DirectDeviceManager import *
|
from DirectDeviceManager import *
|
||||||
@ -291,6 +304,7 @@ class DirectSession(PandaObject):
|
|||||||
self.selectedNPReadout.reparentTo(aspect2d)
|
self.selectedNPReadout.reparentTo(aspect2d)
|
||||||
self.selectedNPReadout.setText(
|
self.selectedNPReadout.setText(
|
||||||
'Selected:' + dnp.name)
|
'Selected:' + dnp.name)
|
||||||
|
self.selectedNPReadout.adjustAllPriorities(100)
|
||||||
# Show the manipulation widget
|
# Show the manipulation widget
|
||||||
self.widget.showWidget()
|
self.widget.showWidget()
|
||||||
# Update camera controls coa to this point
|
# Update camera controls coa to this point
|
||||||
@ -346,6 +360,7 @@ class DirectSession(PandaObject):
|
|||||||
self.activeParentReadout.reparentTo(aspect2d)
|
self.activeParentReadout.reparentTo(aspect2d)
|
||||||
self.activeParentReadout.setText(
|
self.activeParentReadout.setText(
|
||||||
'Active Parent:' + nodePath.getName())
|
'Active Parent:' + nodePath.getName())
|
||||||
|
self.activeParentReadout.adjustAllPriorities(100)
|
||||||
# Alert everyone else
|
# Alert everyone else
|
||||||
messenger.send('DIRECT_activeParent', [self.activeParent])
|
messenger.send('DIRECT_activeParent', [self.activeParent])
|
||||||
|
|
||||||
@ -577,6 +592,23 @@ class DirectSession(PandaObject):
|
|||||||
messenger.send('DIRECT_redo')
|
messenger.send('DIRECT_redo')
|
||||||
|
|
||||||
# UTILITY FUNCTIONS
|
# UTILITY FUNCTIONS
|
||||||
|
def message(self, text):
|
||||||
|
taskMgr.removeTasksNamed('hideDirectMessage')
|
||||||
|
taskMgr.removeTasksNamed('hideDirectMessageLater')
|
||||||
|
self.directMessageReadout.reparentTo(aspect2d)
|
||||||
|
self.directMessageReadout.setText(text)
|
||||||
|
self.directMessageReadout.adjustAllPriorities(100)
|
||||||
|
self.hideDirectMessageLater()
|
||||||
|
|
||||||
|
def hideDirectMessageLater(self):
|
||||||
|
seq = Task.doLater(3.0, Task.Task(self.hideDirectMessage),
|
||||||
|
'hideDirectMessage')
|
||||||
|
t = taskMgr.spawnTaskNamed(seq, 'hideDirectMessageLater')
|
||||||
|
|
||||||
|
def hideDirectMessage(self, state):
|
||||||
|
self.directMessageReadout.reparentTo(hidden)
|
||||||
|
return Task.done
|
||||||
|
|
||||||
def useObjectHandles(self):
|
def useObjectHandles(self):
|
||||||
self.widget = self.manipulationControl.objectHandles
|
self.widget = self.manipulationControl.objectHandles
|
||||||
self.widget.reparentTo(direct.group)
|
self.widget.reparentTo(direct.group)
|
||||||
|
@ -35,7 +35,10 @@ Central Region:
|
|||||||
Up/Down/Left/Right: Moves object in plane parallel to camera's image
|
Up/Down/Left/Right: Moves object in plane parallel to camera's image
|
||||||
plane
|
plane
|
||||||
Shift + LMB:
|
Shift + LMB:
|
||||||
Up/Down: Moves object's COA towards camera
|
Up/Down: Moves object's COA in camera's XY plane
|
||||||
|
Left/Right: Moves object parallel to camera's X axis
|
||||||
|
Control + LMB:
|
||||||
|
Up/Down: Moves object's COA toward Camera (in Y and Z)
|
||||||
Left/Right: Moves object parallel to camera's X axis
|
Left/Right: Moves object parallel to camera's X axis
|
||||||
Alt + LMB (off of widget):
|
Alt + LMB (off of widget):
|
||||||
Away from COA: scale object up
|
Away from COA: scale object up
|
||||||
@ -70,9 +73,25 @@ COA. Hit 'Tab' again to return to normal object manipulation mode.
|
|||||||
|
|
||||||
All camera manipulation performed with middle mouse button (MMB).
|
All camera manipulation performed with middle mouse button (MMB).
|
||||||
|
|
||||||
Window is divided up into three regions: an outer frame, central region, and
|
Camera manipulation depends on where mouse interaction begins and the
|
||||||
the four corners. Camera manipulation depends on where mouse interaction
|
current center of action (COA).
|
||||||
begins.
|
|
||||||
|
The window is divided up into three regions: an outer frame, central region,
|
||||||
|
and the four corners. A different manipulation mode is defined for each
|
||||||
|
region and is described below.
|
||||||
|
|
||||||
|
The camera center of action (COA) determines the center of rotation of any
|
||||||
|
rotation moves and the scale factor for any translation moves.
|
||||||
|
|
||||||
|
The COA is set by quickly clicking (less than .25 second or 1 frame) with
|
||||||
|
the MMB in the central region. It is defined as the intersection point of
|
||||||
|
the ray from the camera's origin, through the mouse with the model. If no
|
||||||
|
intersection occurs, the COA is put out along the camera's Y axis. Each
|
||||||
|
time the MMB is clicked with no intersection the COA moves further out
|
||||||
|
along the Y axis.
|
||||||
|
|
||||||
|
Pressing 'L' toggles COA lock, when on, the COA is locked in its current
|
||||||
|
location.
|
||||||
|
|
||||||
Central Region:
|
Central Region:
|
||||||
MMB:
|
MMB:
|
||||||
@ -85,15 +104,12 @@ Central Region:
|
|||||||
Up/Down/Left/Right: shifts camera in image plane
|
Up/Down/Left/Right: shifts camera in image plane
|
||||||
Outer Region:
|
Outer Region:
|
||||||
MMB:
|
MMB:
|
||||||
Up/Down/Left/Right: Rotates about current COA. The COA is set every
|
Up/Down/Left/Right: Rotates about current COA. If mouse stays within
|
||||||
time you press the MMB in the central region. It is defined as the
|
outer frame, motion about COA is constrained to a single axis.
|
||||||
intersection point of the ray from the camera's origin, through
|
(parallel to camera's X axis when in left and right part of the frame
|
||||||
the mouse with the model (if no intersection, no change in the COA
|
and parallel to the camera's Z axis when in the top or bottom part of
|
||||||
will result). If mouse stays within outer frame, motion about COA
|
the frame)
|
||||||
is constrained to a single axis. (parallel to camera's X axis when
|
Shift + MMB:
|
||||||
in left and right part of the frame and parallel to the camera's Z
|
|
||||||
axis when in the top or bottom part of the frame)
|
|
||||||
Shift MMB:
|
|
||||||
Up/Down: Pitch about camera's X axis
|
Up/Down: Pitch about camera's X axis
|
||||||
Left/Right: Yaw about camera's Z axis
|
Left/Right: Yaw about camera's Z axis
|
||||||
Four corners:
|
Four corners:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user