*** empty log message ***

This commit is contained in:
Mark Mine 2001-06-01 03:46:46 +00:00
parent 21933936d5
commit 11cdb8a6be
6 changed files with 214 additions and 83 deletions

View File

@ -55,7 +55,10 @@ class DirectJoybox(PandaObject):
self.refCS = direct.cameraControl.coaMarker
self.tempCS = direct.group.attachNewNode('JoyboxTempCS')
# 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
self.modeList = [self.joeMode, self.driveMode, self.orbitMode]
# Pick initial mode

View File

@ -8,10 +8,11 @@ Y_AXIS = Vec3(0,1,0)
class DirectCameraControl(PandaObject):
def __init__(self):
# Create the grid
self.startT = 0.0
self.startF = 0
self.orthoViewRoll = 0.0
self.lastView = 0
self.coa = Point3(0,100,0)
self.coaDist = 100
self.coaMarker = loader.loadModel('models/misc/sphere')
self.coaMarker.setName('DirectCameraCOAMarker')
self.coaMarker.setTransparency(1)
@ -19,7 +20,10 @@ class DirectCameraControl(PandaObject):
self.coaMarker.setPos(0,100,0)
useDirectRenderStyle(self.coaMarker)
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')
t = CAM_MOVE_DURATION
self.actionEvents = [
@ -64,13 +68,9 @@ class DirectCameraControl(PandaObject):
# MOUSE IS IN CENTRAL REGION
# Hide the marker for this kind of motion
self.coaMarker.hide()
# 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)
self.computeCOA(node, hitPt, hitPtDist)
# Record time of start of mouse interaction
self.startT= globalClock.getFrameTime()
self.startF = globalClock.getFrameCount()
# Start manipulation
self.spawnXZTranslateOrHPanYZoom()
# END MOUSE IN CENTRAL REGION
@ -85,6 +85,24 @@ class DirectCameraControl(PandaObject):
def mouseFlyStop(self):
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
self.coaMarker.show()
# Resize it
@ -96,7 +114,8 @@ class DirectCameraControl(PandaObject):
# Spawn the new task
t = Task.Task(self.XZTranslateOrHPanYZoomTask)
# 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')
def spawnXZTranslateOrHPPan(self):
@ -117,7 +136,8 @@ class DirectCameraControl(PandaObject):
taskMgr.removeTasksNamed('manipulateCamera')
# Spawn new task
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')
def spawnHPPan(self):
@ -155,15 +175,17 @@ class DirectCameraControl(PandaObject):
def HPanYZoomTask(self,state):
if direct.fControl:
moveDir = Vec3(Y_AXIS)
else:
moveDir = Vec3(self.coaMarker.getPos(direct.camera))
# If marker is behind camera invert vector
if moveDir[1] < 0.0:
moveDir.assign(moveDir * -1)
moveDir.normalize()
else:
moveDir = Vec3(Y_AXIS)
moveDir.assign(moveDir * (-2.0 * direct.dr.mouseDeltaY *
state.zoomSF))
if direct.dr.mouseDeltaY > 0.0:
moveDir.setY(moveDir[1] * 1.0)
direct.camera.setPosHpr(direct.camera,
moveDir[0],
moveDir[1],
@ -247,54 +269,85 @@ class DirectCameraControl(PandaObject):
return Task.cont
def lockCOA(self):
self.fUpdateCOA = 0
self.fLockCOA = 1
direct.message('COA Lock On')
def unlockCOA(self):
self.fUpdateCOA = 1
self.fLockCOA = 0
direct.message('COA Lock Off')
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):
""" Cycle through collision handler entries """
node, hitPt, hitPtDist = direct.iRay.pickNext()
self.computeCOA(node, hitPt, hitPtDist)
if self.cqEntries:
# 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):
coa = Point3(0)
if self.fUpdateCOA and node:
# Set center of action
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:
if self.fLockCOA:
# COA is locked, use existing point
# Use existing point
coa.assign(self.coaMarker.getPos(direct.camera))
coaDist = Vec3(coa - ZERO_POINT).length()
# Check again its not to close
if coaDist < (1.1 * direct.dr.near):
coa.set(0,100,0)
coaDist = 100
# Update coa and marker
self.updateCoa(coa, coaDist)
def updateCoa(self, cam2point, coaDist = None):
self.coa.set(cam2point[0], cam2point[1], cam2point[2])
if coaDist:
self.coaDist = coaDist
# 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:
self.coaDist = Vec3(self.coa - ZERO_POINT).length()
# 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()
if coaDist < (1.1 * direct.dr.near):
coa.set(0,100,0)
coaDist = 100
# Update coa and marker
self.updateCoa(coa, coaDist = coaDist)
def updateCoa(self, ref2point, coaDist = None, ref = None):
self.coa.set(ref2point[0], ref2point[1], ref2point[2])
if not coaDist:
coaDist = Vec3(self.coa - ZERO_POINT).length()
# 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
self.updateCoaMarkerSize(coaDist)
# Record marker pos in render space

View File

@ -231,7 +231,7 @@ class DirectManipulationControl(PandaObject):
else:
# Mouse started in central region, xlate
# Mode depends on shift key
if direct.fShift:
if direct.fShift or direct.fControl:
self.xlateCamXY(state)
else:
self.xlateCamXZ(state)
@ -367,7 +367,11 @@ class DirectManipulationControl(PandaObject):
def xlateCamXY(self, state):
"""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
vWidget2Camera = direct.widget.getPos(direct.camera)
# 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
coaCenter = getNearProjectionPoint(direct.widget)
self.deltaNearX = coaCenter[0] - direct.dr.nearVec[0]
# Reset scaling init flag
self.fScaleInit = 1
# Which way do we move the object?
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
dr = direct.dr
# Move object in y axis based on mouse motion
newY = vWidget2Camera[1] + self.xlateSF * dr.mouseDeltaY
# Put object at same relative point to mouse in X
newX = (direct.dr.nearVec[0] + self.deltaNearX) * (newY/dr.near)
direct.widget.setPos(direct.camera, newX, newY, vWidget2Camera[2])
# Scale move dir
moveDir.assign(moveDir * (2.0 * dr.mouseDeltaY * self.xlateSF))
# Add it to current widget offset
vWidget2Camera += moveDir
# 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):
""" Virtual trackball rotation of widget """

View File

@ -403,6 +403,8 @@ class SelectionRay:
self.ct = CollisionTraverser( RenderRelation.getClassType() )
# Let the traverser know about the queue and the collision node
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
self.unpickable = UNPICKABLE
@ -414,7 +416,8 @@ class SelectionRay:
if item in self.unpickable:
self.unpickable.remove(item)
def pickGeom(self, targetNodePath = render, fIntersectUnpickable = 0):
def pickGeom(self, targetNodePath = render, fIntersectUnpickable = 0,
fIgnoreCamera = 0):
self.collideWithGeom()
self.pick(targetNodePath,
direct.dr.mouseX,
@ -425,9 +428,13 @@ class SelectionRay:
for i in range(0,self.numEntries):
entry = self.cq.getEntry(i)
node = entry.getIntoNode()
nodePath = render.findPathDownTo(node)
# Don't pick hidden nodes
if node.isHidden():
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
elif fIntersectUnpickable:
self.cqIndex = i
@ -448,7 +455,8 @@ class SelectionRay:
if(self.cqIndex >= 0):
# Yes!
# 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()
return (node, hitPt, hitPtDist)
else:
@ -465,7 +473,8 @@ class SelectionRay:
# Entry 0 is the closest hit point if multiple hits
minPt = 0
# Find hit point in parent's space
hitPt = self.parentToHitPt(minPt)
entry = self.cq.getEntry(minPt)
hitPt = self.parentToHitPt(entry)
hitPtDist = Vec3(hitPt).length()
# Get the associated collision queue object
entry = self.cq.getEntry(minPt)
@ -483,15 +492,18 @@ class SelectionRay:
self.ct.traverse( targetNodePath.node() )
self.numEntries = self.cq.getNumEntries()
self.cq.sortEntries()
# Record cam's current position (used for cycling through
# other hit points)
self.collisionRef.iPosHprScale(base.cam)
return self.numEntries
def pickNext(self):
def getHitPt(self, entry):
if self.cqIndex >= 0:
self.cqIndex = (self.cqIndex + 1) % self.numEntries
entry = self.cq.getEntry(self.cqIndex)
node = entry.getIntoNode()
# Find hit point in parent's space
hitPt = self.parentToHitPt(self.cqIndex)
hitPt = self.parentToHitPt(entry)
hitPtDist = Vec3(hitPt - ZERO_POINT).length()
return (node, hitPt, hitPtDist)
else:
@ -530,7 +542,8 @@ class SelectionRay:
if(self.cqIndex >= 0):
# Yes!
# 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()
return (node, hitPt, hitPtDist)
else:
@ -561,9 +574,8 @@ class SelectionRay:
def objectToHitPt(self, index):
return self.cq.getEntry(index).getIntoIntersectionPoint()
def parentToHitPt(self, index):
# Get the specified entry
entry = self.cq.getEntry(index)
def parentToHitPt(self, entry):
# Get hit point
hitPt = entry.getIntoIntersectionPoint()
# Convert point from object local space to parent's space
return entry.getInvWrtSpace().xformPoint(hitPt)

View File

@ -23,6 +23,10 @@ class DirectSession(PandaObject):
# Establish a global pointer to the direct object early on
# so dependant classes can access it in their code
__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.drList = DisplayRegionList()
self.iRayList = map(lambda x: x.iRay, self.drList)
@ -30,7 +34,6 @@ class DirectSession(PandaObject):
self.camera = self.dr.camera
self.iRay = self.dr.iRay
self.group = render.attachNewNode('DIRECT')
self.cameraControl = DirectCameraControl()
self.manipulationControl = DirectManipulationControl()
self.useObjectHandles()
@ -51,18 +54,28 @@ class DirectSession(PandaObject):
self.selectedNPReadout = OnscreenText.OnscreenText(
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
useDirectRenderStyle(self.selectedNPReadout)
self.selectedNPReadout.reparentTo( hidden )
self.activeParentReadout = OnscreenText.OnscreenText(
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
useDirectRenderStyle(self.activeParentReadout)
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
if base.config.GetBool('want-vrpn', 0):
from DirectDeviceManager import *
@ -291,6 +304,7 @@ class DirectSession(PandaObject):
self.selectedNPReadout.reparentTo(aspect2d)
self.selectedNPReadout.setText(
'Selected:' + dnp.name)
self.selectedNPReadout.adjustAllPriorities(100)
# Show the manipulation widget
self.widget.showWidget()
# Update camera controls coa to this point
@ -346,6 +360,7 @@ class DirectSession(PandaObject):
self.activeParentReadout.reparentTo(aspect2d)
self.activeParentReadout.setText(
'Active Parent:' + nodePath.getName())
self.activeParentReadout.adjustAllPriorities(100)
# Alert everyone else
messenger.send('DIRECT_activeParent', [self.activeParent])
@ -577,6 +592,23 @@ class DirectSession(PandaObject):
messenger.send('DIRECT_redo')
# 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):
self.widget = self.manipulationControl.objectHandles
self.widget.reparentTo(direct.group)

View File

@ -35,7 +35,10 @@ Central Region:
Up/Down/Left/Right: Moves object in plane parallel to camera's image
plane
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
Alt + LMB (off of widget):
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).
Window is divided up into three regions: an outer frame, central region, and
the four corners. Camera manipulation depends on where mouse interaction
begins.
Camera manipulation depends on where mouse interaction begins and the
current center of action (COA).
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:
MMB:
@ -85,15 +104,12 @@ Central Region:
Up/Down/Left/Right: shifts camera in image plane
Outer Region:
MMB:
Up/Down/Left/Right: Rotates about current COA. The COA is set every
time you press 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, no change in the COA
will result). If mouse stays within outer frame, motion about COA
is constrained to a single axis. (parallel to camera's X axis when
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/Left/Right: Rotates about current COA. If mouse stays within
outer frame, motion about COA is constrained to a single axis.
(parallel to camera's X axis when 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
Left/Right: Yaw about camera's Z axis
Four corners: