NovaBryan/EVE_Dump
Log | Files | 📦 下载最新源码 (.zip) | Refs | README

charCreationCamera.py (14466B)


      1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\eve\client\script\ui\camera\charCreationCamera.py
      2 import math
      3 import geo2
      4 import blue
      5 import mathext
      6 import signals
      7 import charactercreator.const as ccConst
      8 from carbonui.camera.behaviors.cameraBehavior import CameraBehavior
      9 from carbonui.camera.polarCamera import PolarCamera
     10 from carbonui.util.various_unsorted import GetAttrs
     11 CONTROL_NONE = 0
     12 CONTROL_VERTICAL = 1
     13 CONTROL_BOTH = 2
     14 
     15 class CharCreationCamera(PolarCamera):
     16 
     17     def __init__(self, avatar, modeName = ccConst.CAMERA_MODE_DEFAULT):
     18         PolarCamera.__init__(self)
     19         self.cameraModeChanged = signals.Signal(signalName='cameraModeChanged')
     20         self.frontClip = 0.1
     21         self.backClip = 1000.0
     22         self.pitch = math.pi / 2
     23         self._transformDistance = None
     24         self._transformPOI = None
     25         self._rotateAvatar = None
     26         self._onFocusValue = False
     27         self.moveCallback = None
     28         self.updateFocus = True
     29         self.AddBehavior(CharCreationCameraHandler())
     30         self.focus = (0.0, 0.0, 0.0)
     31         self.xFactor = 0.0
     32         self.yFactor = 0.0
     33         self._currentMode = None
     34         self.ToggleMode(modeName, avatar)
     35 
     36     def ToggleMode(self, modeName, avatar = None, transformTime = None):
     37         self.avatar = avatar
     38         self.UpdateAvatarStats()
     39         self.updateFocus = True
     40         self.xTarget = 0.0
     41         self.yTarget = 0.0
     42         setup = {'controlStyle': CONTROL_NONE,
     43          'farDistance': 1000.0,
     44          'nearDistance': 1.0,
     45          'minRotation': None,
     46          'maxRotation': None,
     47          'fieldOfView': 0.9,
     48          'minPanX': -0.14,
     49          'maxPanX': 0.12,
     50          'minPanY': -0.12,
     51          'maxPanY': 0.12,
     52          'nearPan': 0.0,
     53          'nearFocusY': 0.0,
     54          'farFocusY': 0.0,
     55          'nearMinTilt': 0.0,
     56          'nearMaxTilt': math.pi,
     57          'farMinTilt': 0.0,
     58          'farMaxTilt': math.pi,
     59          'distance': 1.7,
     60          'poi': (0, 1.5, 0),
     61          'rotateAvatar': True}
     62         if modeName in (ccConst.CAMERA_MODE_FACE, ccConst.CAMERA_MODE_BODY):
     63             setup['controlStyle'] = CONTROL_VERTICAL
     64             setup['fieldOfView'] = 0.3
     65             setup['farDistance'] = 8.0
     66             setup['nearDistance'] = 0.9
     67             setup['minPanX'] = 0.0
     68             setup['maxPanX'] = 0.0
     69             setup['minPanY'] = -1.5
     70             setup['maxPanY'] = 0.1
     71             setup['nearPan'] = 0.0
     72             setup['nearFocusY'] = 0.0
     73             setup['farFocusY'] = -self.avatarEyeHeight / 2.0 + 0.1
     74             setup['nearMinTilt'] = math.pi * 0.4
     75             setup['nearMaxTilt'] = math.pi * 0.66
     76             setup['farMinTilt'] = math.pi * 0.5
     77             setup['farMaxTilt'] = math.pi * 0.5
     78             if modeName == ccConst.CAMERA_MODE_FACE:
     79                 setup['distance'] = setup['nearDistance'] + 0.5
     80                 setup['poi'] = (0, -setup['nearFocusY'], 0)
     81                 setup['yFactor'] = setup['nearFocusY']
     82             else:
     83                 setup['distance'] = setup['farDistance']
     84                 setup['poi'] = (0, -setup['farFocusY'], 0)
     85                 setup['yFactor'] = setup['farFocusY']
     86         elif modeName == ccConst.CAMERA_MODE_PORTRAIT:
     87             setup['controlStyle'] = CONTROL_BOTH
     88             setup['minRotation'] = 1.0
     89             setup['maxRotation'] = 2.5
     90             setup['fieldOfView'] = 0.3
     91             setup['farDistance'] = 2.5
     92             setup['nearDistance'] = 0.6
     93             setup['minPanX'] = -0.2
     94             setup['maxPanX'] = 0.2
     95             setup['minPanY'] = -0.15
     96             setup['maxPanY'] = 0.15
     97             setup['nearPan'] = 0.07
     98             setup['nearFocusY'] = 0.0
     99             setup['farFocusY'] = 0.0
    100             setup['nearMinTilt'] = math.pi * 0.33
    101             setup['nearMaxTilt'] = math.pi * 0.66
    102             setup['farMinTilt'] = math.pi * 0.33
    103             setup['farMaxTilt'] = math.pi * 0.66
    104             setup['distance'] = setup['nearDistance'] + 0.5
    105             setup['rotateAvatar'] = False
    106         self._transformDistance = None
    107         self._transformPOI = None
    108         if (self._rotateAvatar is None or self._rotateAvatar != setup['rotateAvatar']) and self.avatar:
    109             self.avatar.rotation = (0, 0, 0, 1)
    110             self.yaw = math.pi / 2
    111         self._rotateAvatar = setup['rotateAvatar']
    112         now = blue.os.GetWallclockTime()
    113         for k, v in setup.iteritems():
    114             if transformTime:
    115                 if k == 'distance':
    116                     self._transformDistance = (now,
    117                      self.distance,
    118                      v,
    119                      transformTime)
    120                 elif k == 'poi':
    121                     self._transformPOI = (now,
    122                      (0.0, -self.yFactor, 0.0),
    123                      v,
    124                      transformTime)
    125                     self._onFocusValue = True
    126                 else:
    127                     setattr(self, k, v)
    128             else:
    129                 setattr(self, k, v)
    130 
    131         self._ChangeMode(modeName)
    132 
    133     def _ChangeMode(self, newMode):
    134         previousMode = self._currentMode
    135         self._currentMode = newMode
    136         if previousMode != self._currentMode:
    137             self.cameraModeChanged(previousMode, self._currentMode)
    138 
    139     def UpdatePortraitInfo(self):
    140         self.UpdateAvatarStats()
    141         self.nearFocusY = self.avatarEyeHeight
    142         self.farFocusY = self.avatarEyeHeight
    143 
    144     def UpdateAvatar(self, avatar):
    145         self.avatar = avatar
    146 
    147     def GetBonePosition(self, boneName):
    148         if self.avatar is not None and self.avatar.animationUpdater is not None:
    149             joint = self.avatar.GetBoneIndex(boneName)
    150             if joint == 4294967295L:
    151                 return (0.0, 0.0, 0.0)
    152             ret = self.avatar.GetBonePosition(joint)
    153             return ret
    154         return (0.0, 0.0, 0.0)
    155 
    156     def UpdateAvatarStats(self):
    157         if self.avatar is not None and self.avatar.animationUpdater is not None:
    158             blue.resMan.Wait()
    159             pos = self.GetBonePosition('fj_eyeballRight')
    160             self.avatarEyeHeight = pos[1]
    161         else:
    162             self.avatarEyeHeight = 0.0
    163 
    164     def PlacePortraitCamera(self, pos, poi):
    165         direction = geo2.Subtract(pos, poi)
    166         self.distance = geo2.Vec3Length(direction)
    167         direction = geo2.Vec3Normalize(direction)
    168         self.yaw = math.acos(direction[0])
    169         self.pitch = math.asin(direction[1]) + math.pi / 2.0
    170         right = self.GetBonePosition('fj_eyeballRight')
    171         left = self.GetBonePosition('fj_eyeballLeft')
    172         self.focus = geo2.Add(right, left)
    173         self.focus = geo2.Vector(*self.focus) * 0.5
    174         xFactor, yFactor = self.GetCorrectCameraXandYFactors(pos, poi)
    175         self.xFactor = xFactor
    176         self.yFactor = yFactor
    177 
    178     def GetCorrectCameraXandYFactors(self, position, poi):
    179         cameraZ = geo2.Vec3Normalize(geo2.Subtract(position, poi))
    180         cameraX = geo2.Vec3Cross(cameraZ, (0.0, 1.0, 0.0))
    181         cameraY = geo2.Vec3Cross(cameraZ, cameraX)
    182         cameraMatrix = ((cameraX[0],
    183           cameraY[0],
    184           cameraZ[0],
    185           0.0),
    186          (cameraX[1],
    187           cameraY[1],
    188           cameraZ[1],
    189           0.0),
    190          (cameraX[2],
    191           cameraY[2],
    192           cameraZ[2],
    193           0.0),
    194          (0.0, 0.0, 0.0, 1.0))
    195         offset = geo2.Subtract(self.focus, poi)
    196         res = geo2.Vec3Transform(offset, cameraMatrix)
    197         return (res[0], res[1])
    198 
    199     def Zoom(self, delta):
    200         newFov = self.fieldOfView + delta * 0.0005
    201         newFov = min(self.maxFov, max(self.minFov, newFov))
    202         self.fieldOfView = newFov
    203         self.xFactor = self.xTarget
    204         self.yFactor = self.yTarget
    205 
    206     def Dolly(self, delta):
    207         if self.controlStyle == CONTROL_NONE:
    208             return
    209         if self.controlStyle == CONTROL_BOTH:
    210             self.xFactor = self.xTarget
    211             self.yFactor = self.yTarget
    212         newDistance = min(self.farDistance, max(self.nearDistance, self.distance - self.distance * (delta * 0.0025)))
    213         self.distance = newDistance
    214         if self._currentMode == ccConst.CAMERA_MODE_FACE and newDistance > 0.75 * self.farDistance:
    215             self._ChangeMode(ccConst.CAMERA_MODE_BODY)
    216         elif self._currentMode == ccConst.CAMERA_MODE_BODY and newDistance < self.nearDistance + 0.5:
    217             self._ChangeMode(ccConst.CAMERA_MODE_FACE)
    218         if self._onFocusValue:
    219             portion = self.GetPortionFromDistance()
    220             self.yFactor = mathext.lerp(self.nearFocusY, self.farFocusY, portion)
    221 
    222     def GetPortionFromDistance(self):
    223         minmaxRange = self.farDistance - self.nearDistance
    224         portion = (self.distance - self.nearDistance) / minmaxRange
    225         return portion
    226 
    227     def GetPortionFromFieldOfView(self):
    228         minmaxRange = self.maxFov - self.minFov
    229         portion = (self.fieldOfView - self.minFov) / minmaxRange
    230         return portion
    231 
    232     def GetFocusYBasedOnDistance(self):
    233         portion = self.GetPortionFromDistance()
    234         focusRange = self.farFocusY - self.nearFocusY
    235         return self.nearFocusY + focusRange * portion
    236 
    237     def GetMinMaxPitchBasedOnDistance(self):
    238         portion = self.GetPortionFromDistance()
    239         minRange = self.farMinTilt - self.nearMinTilt
    240         maxRange = self.farMaxTilt - self.nearMaxTilt
    241         return (self.nearMinTilt + minRange * portion, self.nearMaxTilt + maxRange * portion)
    242 
    243     def Pan(self, dx, dy):
    244         if self.controlStyle == CONTROL_NONE:
    245             return
    246         self.xFactor -= dx * 0.0005
    247         self.yFactor += dy * 0.0005 * self.distance
    248         self.xTarget = self.xFactor
    249         self.yTarget = self.yFactor
    250         self._onFocusValue = False
    251 
    252     def GetPanLimitsBasedOnDistance(self):
    253         if self.controlStyle == CONTROL_VERTICAL:
    254             portion = 1.0
    255         else:
    256             portion = self.GetPortionFromDistance()
    257         return ((self.minPanX * portion - self.nearPan, self.maxPanX * portion + self.nearPan), (self.minPanY * portion - self.nearPan, self.maxPanY * portion + self.nearPan))
    258 
    259     def LimitPanning(self):
    260         xLimits, yLimits = self.GetPanLimitsBasedOnDistance()
    261         if self.controlStyle == CONTROL_BOTH:
    262             xAxis = geo2.Vector(self.viewMatrix.transform[0][0], self.viewMatrix.transform[1][0], self.viewMatrix.transform[2][0])
    263             yAxis = geo2.Vector(self.viewMatrix.transform[0][1], self.viewMatrix.transform[1][1], self.viewMatrix.transform[2][1])
    264         else:
    265             xAxis = geo2.Vector(1.0, 0.0, 0.0)
    266             yAxis = geo2.Vector(0.0, 1.0, 0.0)
    267         self.xFactor = min(xLimits[1], max(xLimits[0], self.xFactor))
    268         self.yFactor = min(yLimits[1], max(yLimits[0], self.yFactor))
    269         horizontal = xAxis * self.xFactor
    270         vertical = yAxis * self.yFactor
    271         offset = horizontal + vertical
    272         rotatedFocus = geo2.QuaternionTransformVector(self.avatar.rotation, self.focus)
    273         newPoi = rotatedFocus + offset
    274         self.SetPointOfInterest(newPoi)
    275 
    276     def AdjustYaw(self, delta):
    277         if self.controlStyle == CONTROL_NONE:
    278             return
    279         if self._rotateAvatar:
    280             delta = delta * 0.005
    281             yaw, pitch, roll = geo2.QuaternionRotationGetYawPitchRoll(self.avatar.rotation)
    282             yaw = yaw + delta
    283             if self.maxRotation is not None and self.minRotation is not None:
    284                 if yaw < math.pi:
    285                     yaw = min(yaw, self.minRotation)
    286                 else:
    287                     yaw = max(yaw, self.maxRotation)
    288             rotation = geo2.QuaternionRotationSetYawPitchRoll(yaw, pitch, roll)
    289             self.avatar.rotation = rotation
    290             charSvc = sm.GetService('character')
    291             if GetAttrs(charSvc, 'sculpting', 'highlightGhost', 'avatar'):
    292                 charSvc.sculpting.highlightGhost.avatar.rotation = rotation
    293             if GetAttrs(charSvc, 'sculpting', 'bodyHighlightGhost', 'avatar'):
    294                 charSvc.sculpting.bodyHighlightGhost.avatar.rotation = rotation
    295             self.Update()
    296         else:
    297             PolarCamera.AdjustYaw(self, delta * 0.005)
    298 
    299     def SetYaw(self, yaw, ignoreUpdate = True):
    300         if self.maxRotation is not None and self.minRotation is not None:
    301             yaw = max(self.minRotation, min(self.maxRotation, yaw))
    302         PolarCamera.SetYaw(self, yaw)
    303 
    304     def AdjustPitch(self, delta):
    305         if self.controlStyle == CONTROL_NONE:
    306             return
    307         self.minPitch, self.maxPitch = self.GetMinMaxPitchBasedOnDistance()
    308         PolarCamera.AdjustPitch(self, delta * 0.005)
    309 
    310     def Update(self):
    311         if self.updateFocus:
    312             right = self.GetBonePosition('fj_eyeballRight')
    313             left = self.GetBonePosition('fj_eyeballLeft')
    314             self.focus = geo2.Add(right, left)
    315             self.focus = geo2.Vector(*self.focus) * 0.5
    316         if self.moveCallback:
    317             self.moveCallback(self.viewMatrix)
    318         if self.controlStyle == CONTROL_VERTICAL:
    319             length = geo2.Vec2Length(geo2.Vector(self.focus[0], self.focus[2]))
    320             self.focus = (0.0, self.focus[1], length)
    321             self.updateFocus = False
    322         PolarCamera.Update(self)
    323 
    324     def SetMoveCallback(self, cb):
    325         self.moveCallback = cb
    326 
    327 
    328 class CharCreationCameraHandler(CameraBehavior):
    329 
    330     def __init__(self):
    331         CameraBehavior.__init__(self)
    332 
    333     @staticmethod
    334     def GetName(self):
    335         return 'CharCreationCameraHandler'
    336 
    337     def ProcessCameraUpdate(self, camera, now, frameTime):
    338         if camera._transformDistance:
    339             startTime, startValue, toValue, duration = camera._transformDistance
    340             ndt = min(1.0, blue.os.TimeDiffInMs(startTime, blue.os.GetWallclockTime()) / duration)
    341             camera.distance = mathext.lerp(startValue, toValue, ndt)
    342             if ndt >= 1.0:
    343                 camera._transformDistance = None
    344         if camera._transformPOI:
    345             startTime, startValue, toValue, duration = camera._transformPOI
    346             ndt = min(1.0, blue.os.TimeDiffInMs(startTime, blue.os.GetWallclockTime()) / duration)
    347             camera.yFactor = mathext.lerp(-startValue[1], -toValue[1], ndt)
    348             if ndt >= 1.0:
    349                 camera._transformPOI = None
    350         if camera.controlStyle != CONTROL_NONE:
    351             camera.minPitch, camera.maxPitch = camera.GetMinMaxPitchBasedOnDistance()
    352             camera.pitch = min(camera.maxPitch, max(camera.minPitch, camera.pitch))
    353             camera.LimitPanning()
    354         camera.UpdateProjectionMatrix()