from pyfbsdk import * from math import sqrt ########################### # Misc/Helper functions ########################### gRBClass = "KxL_RigidBodyProperty" gJClass = "KxL_JointBasicProperty" gSClass = "KxL_PhysicsSolver" gConstraintManager = FBConstraintManager() def GetPhysicsProperty( pModel, pPropertyClassName ): if pPropertyClassName != None and pModel != None: for lComp in pModel.Components: if lComp and lComp.ClassName() == pPropertyClassName: return lComp return None def FastRBModelTest( pModel ): if pModel.ClassName() == "FBModel" or pModel.ClassName() == "FBModelMarker" or (pModel.ClassName() == "FBModelNull" and len(pModel.Children) > 0): return True else: return False def SetJointModels( pJointModel, pJointProperty, pConnectionList ): lConnections = None lName = pJointModel.Name +" Joint" for lComp in pJointProperty.Components: if lComp.Name == lName: lConnections = lComp.PropertyList.Find("Connections",False) if lConnections != None: for lModel in pConnectionList: if lModel: FBConnect(lModel,lConnections) def GetSolver( pActive, pLive): for lSolver in FBSystem().Scene.ConstraintSolvers: if lSolver.ClassName() == gSClass and lSolver.Active == pActive and lSolver.Live == pLive: return lSolver return None def GetExtraParamValue(pParamName, pExtraParams, pDefaultValue): if pParamName in pExtraParams: return pExtraParams[pParamName] else: return pDefaultValue def GetMappingKey(pDict, pValue): return [key for key, value in pDict.iteritems() if value == pValue][0] ########################### # Little math ########################### def GetCenter( pModelList ): lCenter = FBVector3d(0,0,0) tmpV = FBVector3d() for lModel in pModelList: lModel.GetVector(tmpV) lCenter[0]+=tmpV[0] lCenter[1]+=tmpV[1] lCenter[2]+=tmpV[2] lCount = len(pModelList) lCenter[0]/=lCount lCenter[1]/=lCount lCenter[2]/=lCount return lCenter def GetLength(pV): return sqrt(pV[0]*pV[0]+pV[1]*pV[1]+pV[2]*pV[2]) def GetNormalized(pV): lLength = GetLength(pV) if lLength != 0: return FBVector3d(pV[0]/lLength,pV[1]/lLength,pV[2]/lLength) else: return FBVector3d(1,0,0) def GetCross(pV1, pV2): return FBVector3d(pV1[1]*pV2[2] - pV1[2]*pV2[1], pV1[2]*pV2[0] - pV1[0]*pV2[2], pV1[0]*pV2[1] - pV1[1]*pV2[0]) def GetDirectionMatrix(pDir, pPos): lDir_X = FBVector3d() lDir_Y = FBVector3d() lDir_Z = GetNormalized(pDir) if(lDir_Z[2] > - 0.9999999 and lDir_Z[2] < 0.9999999): lDir_Y = GetNormalized(FBVector3d(lDir_Z[0]*lDir_Z[2],lDir_Z[1]*lDir_Z[2],(lDir_Z[2]*lDir_Z[2])+1)) lDir_X = GetNormalized(GetCross(lDir_Y,lDir_Z)) lDir_Y = GetNormalized(GetCross(lDir_Z,lDir_X)) else: lDir_X = GetNormalized(FBVector3d(lDir_Z[2],0,-lDir_Z[0])) lDir_Y[1] = 1 lM = FBMatrix() for i in range(0,3): lM[i] = lDir_X[i] lM[4+i] = lDir_Y[i] lM[8+i] = lDir_Z[i] lM[12+i] = pPos[i] return lM ########################### # Physics property creation (this nice function let you create objects that are not accessible from ORSDK/Python ########################### def CreateRigidBodyP(): return FBCreateObject("Browsing/Templates/Physical Properties", "Rigid Body","Rigid Body" ) def CreateJointP(): return FBCreateObject("Browsing/Templates/Physical Properties", "Joint", "Joint" ) def CreatePhysicsSolver(): return FBCreateObject("Browsing/Templates/Solvers", "Physics Solver","Physics Solver" ) def GetAnySolver(): lSolver = GetSolver(True,True) if lSolver == None: lSolver = GetSolver(True,False) if lSolver == None: lSolver = GetSolver(False,False) if lSolver == None: lSolver = CreatePhysicsSolver() return lSolver ########################### # This function let you attach RB property to given model. # If RB property not passed, new one will be created ########################### def SetModelAsRigidBody( pModel, pRigidBodyProperty ): lAttachedRB = GetPhysicsProperty( pModel, gRBClass ) if lAttachedRB: FBDisconnect(lAttachedRB,pModel) if FastRBModelTest( pModel ): if pRigidBodyProperty == None: pRigidBodyProperty = CreateRigidBodyP() FBConnect(pRigidBodyProperty,pModel) return pRigidBodyProperty return None ########################### # Change given RB model activation. ########################### def SetRBModelActivation( pRBModel, pState, pAutoConvertToRB ): lRBProperty = GetPhysicsProperty( pRBModel, gRBClass ) if lRBProperty == None and pAutoConvertToRB: lRBProperty = SetModelAsRigidBody(pRBModel) if lRBProperty != None: lRBProperty.PropertyList.Find("Activation",False).Data = pState ########################### # Here we connect given models with joint. ########################### def MakeJointOnModel( pConnectModels, pJointProperty ): if len(pConnectModels) == 0: print "Give at least one RB models." else: if pJointProperty == None: pJointProperty = CreateJointP() lJModel = FBModelNull("Joint Model") lJModel.Size = 400 lJModel.SetVector(GetCenter(pConnectModels)) lJModel.Show = True FBConnect(pJointProperty, lJModel) SetJointModels(lJModel,pJointProperty,pConnectModels) ########################### # Joint chains...good for tails, hairs, etc ########################### def CreateParentChildConstraint(pConstraintManager): for lIdx in range( pConstraintManager.TypeGetCount() ): if pConstraintManager.TypeGetName(lIdx) == 'Parent/Child': return pConstraintManager.TypeCreateConstraint(lIdx) return None def CreateChainBetween(pModel1, pModel2, pParentRBModel, pRigidBodyP, pJointP, **pExtraParams): #Radius, GlobalRadius, PinRoot, ExtraParentForRoot, ConstraintSkeleton lV1 = FBVector3d() pModel1.GetVector(lV1) lMatrix = FBMatrix() lRB_Model = None if pModel2: # Compute RigidBody model size and pos lV2 = FBVector3d() pModel2.GetVector(lV2) lDir = FBVector3d(lV2[0] - lV1[0],lV2[1] - lV1[1],lV2[2] - lV1[2]) lCenter = FBVector3d(lV1[0] + lDir[0]/2, lV1[1] + lDir[1]/2, lV1[2] + lDir[2]/2) lLength = GetLength(lDir)*100 lRadius = GetExtraParamValue('Radius',pExtraParams,5) if GetExtraParamValue('GlobalRadius',pExtraParams,True): lRadius *= 100 else: lRadius *= lLength # Create RigidBody model lRB_Model = FBModelMarker("Chain RB") lRB_Model.Look = FBMarkerLook.kFBMarkerLookCapsule lRB_Model.Size = lRadius lRB_Model.Length = lLength lMatrix = GetDirectionMatrix(lDir,lCenter) lRB_Model.SetMatrix(lMatrix) lRB_Model.Show = True FBConnect(pRigidBodyP, lRB_Model) else: pModel1.GetMatrix(lMatrix,FBModelTransformationMatrix.kModelRotation) if pParentRBModel or GetExtraParamValue('PinRoot',pExtraParams,False) or GetExtraParamValue('ExtraParentForRoot',pExtraParams,None) != None: # Create Joint model lJ_Model = FBModelNull("Chain J") lJ_Model.Size = 400 lJ_Model.SetVector(lV1) lJ_Model.SetMatrix(lMatrix,FBModelTransformationMatrix.kModelRotation) lJ_Model.Show = True FBConnect(pJointP, lJ_Model) # Setup Joint if pParentRBModel: SetJointModels(lJ_Model,pJointP,[pParentRBModel,lRB_Model]) else: SetJointModels(lJ_Model,pJointP,[GetExtraParamValue('ExtraParentForRoot',pExtraParams,None),lRB_Model]) # Constrain skeleton to RB models if lRB_Model and GetExtraParamValue('ConstraintSkeleton',pExtraParams,False): lCnst = CreateParentChildConstraint(gConstraintManager) lCnst.ReferenceAdd(0,pModel1) lCnst.ReferenceAdd(1,lRB_Model) #lCnst.Snap() #lCnst.Lock = True return lRB_Model def CreateChain(pParentChainModel, pParentRBModel, pRigidBodyP, pJointP, **pExtraParams): #PinLeafs #Radius, GlobalRadius, PinRoot, ExtraParentForRoot, ConstraintSkeleton if len(pParentChainModel.Children) > 0: for lChild in pParentChainModel.Children: lRB_Model = CreateChainBetween(pParentChainModel, lChild, pParentRBModel, pRigidBodyP, pJointP, **pExtraParams) CreateChain(lChild,lRB_Model, pRigidBodyP, pJointP, **pExtraParams) elif GetExtraParamValue('PinLeafs',pExtraParams,False): CreateChainBetween(pParentChainModel, None, pParentRBModel, pRigidBodyP, pJointP, **pExtraParams) ########################### # Solver control ########################### gSolveOperation = { 0 : 'Online', 1 : 'Live', 2 : 'Reset', 3 : 'SetStart' } def SetSolver( pSolver, pOperation, **pExtraParam): #SetOnline SetLive Reset if pSolver != None: lOperationIndex = GetMappingKey(gSolveOperation,pOperation) if lOperationIndex == 0: if 'SetOnline' in pExtraParam: lSetOnline = pExtraParam['SetOnline'] if lSetOnline == False: if pSolver.Active and GetExtraParamValue('Reset',pExtraParam,False): pSolver.PropertyList.Find("Reset to start",False)() pSolver.Active = lSetOnline return True elif lOperationIndex == 1: if 'SetLive' in pExtraParam: lLive = pExtraParam['SetLive'] if lLive: if pSolver.Active == False: pSolver.Active = True pSolver.Live = lLive return True elif lOperationIndex == 2: if pSolver.Active == True: pSolver.PropertyList.Find("Reset to start",False)() return True elif lOperationIndex == 3: if pSolver.Active == True: pSolver.PropertyList.Find("Set start state",False)() return True return False ########################### # Selected models operations ########################### gModelOperation = { 0 : 'MakeRB', 1 : 'MakeJoint', 2 : 'ChangeActivation', 3 : 'ConvertToChain' } def CallOnSelection( pOperation, **pExtraParams): #RigidBodyProperty, JointProperty #PinLeafs #Radius, GlobalRadius, PinRoot, ExtraParentForRoot, ConstraintSkeleton lModelList = FBModelList() FBGetSelectedModels(lModelList) if len(lModelList) > 0: lOperationIndex = GetMappingKey(gModelOperation,pOperation) if lOperationIndex == 0: lRigidBodyP = GetExtraParamValue('RigidBodyProperty',pExtraParams,None) if lRigidBodyP == None: lRigidBodyP = CreateRigidBodyP() for lModel in lModelList: SetModelAsRigidBody(lModel,lRigidBodyP) return True elif lOperationIndex == 1: lJointP = GetExtraParamValue('JointProperty',pExtraParams,None) MakeJointOnModel(lModelList,lJointP) return True elif lOperationIndex == 2: if 'Type' in pExtraParams: lActivationType = pExtraParams['Type'] lAutoConvert = GetExtraParamValue('AutoConvert',pExtraParams,False) for lModel in lModelList: SetRBModelActivation(lModel,lActivationType,lAutoConvert) return True elif lOperationIndex == 3: if len(lModelList) > 1: print 'Only first model is used for chain creation!' lRigidBodyP = GetExtraParamValue('RigidBodyProperty',pExtraParams,None) lJointP = GetExtraParamValue('JointProperty',pExtraParams,None) if lRigidBodyP == None: lRigidBodyP = CreateRigidBodyP() if lJointP == None: lJointP = CreateJointP() CreateChain(lModelList[0], None, lRigidBodyP, lJointP, **pExtraParams) return True return False ######################################## ######################################## # TOOL (added to the same file for simplicity) # This tool only shows small amout of what is possible # with above functions. It's nothing fancy, because main # speedup is achieved by combining those functions # and attaching to shortcuts. ######################################## ######################################## from pyfbsdk_additions import * gToolName = "Physics Speedup scripts" gDevelopment = True class PhysicsSpeedupTool(FBTool): # For callbacks def ContainerDrop(self, pEvent, pContainer, pMember, pAccept, pClassType=None): if pEvent.State == FBDragAndDropState.kFBDragAndDropDrag: if (pAccept and pEvent.Components[0].ClassName() == pAccept) or (pClassType and pEvent.Components[0].Is(pClassType)): pEvent.Accept() elif pEvent.State == FBDragAndDropState.kFBDragAndDropDrop: self.ContainerClear(pContainer,pMember) pMember.append(pEvent.Components[0]) pContainer.Items.append(pEvent.Components[0].Name) def ContainerClear(self, pContainer, pMember): if len(pMember): pMember.pop() pContainer.Items.removeAll() def GetObject(self,pMember): if len(pMember): return pMember[0] return None # Members. def CreateMembers(self): self.mRB_Prop = [] self.mJ_Prop = [] self.mExtraParent = [] self.mBtnMakeRB = FBButton() self.mBtnMakeJ = FBButton() self.mBtnSetActive = FBButton() self.mBtnSetAtCollision = FBButton() self.mBtnSetPassive = FBButton() self.mBtnSetOnline = FBButton() self.mBtnSetOffline = FBButton() self.mBtnRunLive = FBButton() self.mBtnStopLive = FBButton() self.mBtnMakeChain = FBButton() self.mLblRadius = FBLabel() self.mEdtRadius = FBEditNumber() self.mBtnGlobalRadius = FBButton() self.mLblPin = FBLabel() self.mBtnPinRoot = FBButton() self.mBtnPinLeafs = FBButton() self.mLblRB_Prop = FBLabel() self.mCntRB_Prop = FBContainer() self.mLblJ_Prop = FBLabel() self.mCntJ_Prop = FBContainer() self.mLblExtraParent = FBLabel() self.mCntExtraParent = FBContainer() self.mBtnConstrainSkeleton = FBButton() self.mBtnMakeRB.Caption = "Make RB" self.mBtnMakeJ.Caption = "Make Joint" self.mBtnSetActive.Caption = "Active" self.mBtnSetAtCollision.Caption = "AtCollision" self.mBtnSetPassive.Caption = "Passive" self.mBtnSetOnline.Caption = "Reset" self.mBtnSetOffline.Caption = "Offline+Reset" self.mBtnRunLive.Caption = "LIVE" self.mBtnStopLive.Caption = "STOP" self.mBtnMakeChain.Caption = "Make chain" self.mLblRadius.Caption = "Radius:" self.mBtnGlobalRadius.Caption = "global" self.mLblPin.Caption = "Pin: " self.mBtnPinRoot.Caption = "root" self.mBtnPinLeafs.Caption = "leafs" self.mLblRB_Prop.Caption = "RB:" self.mLblJ_Prop.Caption = "J:" self.mLblExtraParent.Caption = "Extra parent:" self.mBtnConstrainSkeleton.Caption = "Constraint skeleton" self.mBtnGlobalRadius.Style = FBButtonStyle.kFB2States self.mBtnGlobalRadius.Look = FBButtonLook.kFBLookColorChange self.mBtnGlobalRadius.Justify = FBTextJustify.kFBTextJustifyCenter self.mBtnGlobalRadius.SetStateColor(FBButtonState.kFBButtonState0,FBColor(0.7, 0.7, 0.7)) self.mBtnPinRoot.Style = FBButtonStyle.kFB2States self.mBtnPinRoot.Look = FBButtonLook.kFBLookColorChange self.mBtnPinRoot.Justify = FBTextJustify.kFBTextJustifyCenter self.mBtnPinRoot.SetStateColor(FBButtonState.kFBButtonState0,FBColor(0.7, 0.7, 0.7)) self.mBtnPinLeafs.Style = FBButtonStyle.kFB2States self.mBtnPinLeafs.Look = FBButtonLook.kFBLookColorChange self.mBtnPinLeafs.Justify = FBTextJustify.kFBTextJustifyCenter self.mBtnPinLeafs.SetStateColor(FBButtonState.kFBButtonState0,FBColor(0.7, 0.7, 0.7)) self.mBtnConstrainSkeleton.Style = FBButtonStyle.kFB2States self.mBtnConstrainSkeleton.Look = FBButtonLook.kFBLookColorChange self.mBtnConstrainSkeleton.Justify = FBTextJustify.kFBTextJustifyCenter self.mBtnConstrainSkeleton.SetStateColor(FBButtonState.kFBButtonState0,FBColor(0.7, 0.7, 0.7)) self.mCntRB_Prop.ItemWidth = 60 self.mCntJ_Prop.ItemWidth = 60 self.mCntExtraParent.ItemWidth = 60 self.mEdtRadius.Value = 5 self.mBtnGlobalRadius.State = 1 self.mBtnMakeRB.OnClick.Add(lambda control = None, event = None : CallOnSelection('MakeRB',RigidBodyProperty=self.GetObject(self.mRB_Prop))) self.mBtnMakeJ.OnClick.Add(lambda control = None, event = None : CallOnSelection('MakeJoint',JointProperty=self.GetObject(self.mJ_Prop))) self.mBtnSetActive.OnClick.Add(lambda control = None, event = None : CallOnSelection('ChangeActivation',Type=0,AutoConvert=False)) self.mBtnSetAtCollision.OnClick.Add(lambda control = None, event = None : CallOnSelection('ChangeActivation',Type=1,AutoConvert=False)) self.mBtnSetPassive.OnClick.Add(lambda control = None, event = None : CallOnSelection('ChangeActivation',Type=2,AutoConvert=False)) self.mBtnSetOnline.OnClick.Add(lambda control = None, event = None : SetSolver(GetAnySolver(),'Reset')) self.mBtnSetOffline.OnClick.Add(lambda control = None, event = None : SetSolver(GetAnySolver(),'Online',SetOnline=False,Reset=True)) self.mBtnRunLive.OnClick.Add(lambda control = None, event = None : SetSolver(GetAnySolver(),'Live',SetLive=True)) self.mBtnStopLive.OnClick.Add(lambda control = None, event = None : SetSolver(GetAnySolver(),'Live',SetLive=False)) self.mBtnMakeChain.OnClick.Add(lambda control = None, event = None : CallOnSelection('ConvertToChain', RigidBodyProperty=self.GetObject(self.mRB_Prop), JointProperty=self.GetObject(self.mJ_Prop), ExtraParentForRoot=self.GetObject(self.mExtraParent), Radius=self.mEdtRadius.Value, GlobalRadius=self.mBtnGlobalRadius.State==1,ConstraintSkeleton=self.mBtnConstrainSkeleton.State==1, PinRoot=self.mBtnPinRoot.State==1,PinLeafs=self.mBtnPinLeafs.State==1)) self.mCntRB_Prop.OnDragAndDrop.Add(lambda control = None, event = None : self.ContainerDrop(event,self.mCntRB_Prop,self.mRB_Prop, gRBClass)) self.mCntRB_Prop.OnDblClick.Add(lambda control = None, event = None : self.ContainerClear(self.mCntRB_Prop,self.mRB_Prop)) self.mCntJ_Prop.OnDragAndDrop.Add(lambda control = None, event = None : self.ContainerDrop(event,self.mCntJ_Prop,self.mJ_Prop, gJClass)) self.mCntJ_Prop.OnDblClick.Add(lambda control = None, event = None : self.ContainerClear(self.mCntJ_Prop,self.mJ_Prop)) self.mCntExtraParent.OnDragAndDrop.Add(lambda control = None, event = None : self.ContainerDrop(event,self.mCntExtraParent,self.mExtraParent, None, FBModel_TypeInfo())) self.mCntExtraParent.OnDblClick.Add(lambda control = None, event = None : self.ContainerClear(self.mCntExtraParent,self.mExtraParent)) # Setup UI. def BuildArrowLayout(self, pH, pName, pLayout, pLast, pLastAttach): x = FBAddRegionParam(5,FBAttachType.kFBAttachLeft,"") y = FBAddRegionParam(5,pLastAttach,pLast) w = FBAddRegionParam(0,FBAttachType.kFBAttachNone,"") h = FBAddRegionParam(0,FBAttachType.kFBAttachNone,"") self.AddRegion(pName ,pName , x, y, w, h) lArrow = FBArrowButton() self.SetControl(pName ,lArrow) lArrow.SetContent( pName, pLayout, 220, pH+6 ) def BuildLayout(self): self.mLytMake = VBoxLayout() self.mLytSet = VBoxLayout() self.mLytPlay = VBoxLayout() self.mLytChain = VBoxLayout() self.BuildArrowLayout(50,"Make",self.mLytMake,"",FBAttachType.kFBAttachTop) self.BuildArrowLayout(25,"Set",self.mLytSet,"Make",FBAttachType.kFBAttachBottom) self.BuildArrowLayout(50,"Play",self.mLytPlay,"Set",FBAttachType.kFBAttachBottom) self.BuildArrowLayout(125,"Chain",self.mLytChain,"Play",FBAttachType.kFBAttachBottom) self.mLytMake.Add(self.mBtnMakeRB,20) self.mLytMake.Add(self.mBtnMakeJ,20) lHLt = HBoxLayout(FBAttachType.kFBAttachLeft) lHLt.AddRelative(self.mBtnSetActive,0.333) lHLt.AddRelative(self.mBtnSetAtCollision,0.333) lHLt.AddRelative(self.mBtnSetPassive,0.333) self.mLytSet.Add(lHLt,20) self.mLytPlay.Add(self.mBtnRunLive,20) lHLt = HBoxLayout(FBAttachType.kFBAttachLeft) lHLt.AddRelative(self.mBtnSetOnline,0.30) lHLt.AddRelative(self.mBtnSetOffline,0.4) lHLt.AddRelative(self.mBtnStopLive,0.30) self.mLytPlay.Add(lHLt,20) self.mLytChain.Add(self.mBtnMakeChain,20) lHLt = HBoxLayout(FBAttachType.kFBAttachLeft) lHLt.AddRelative(self.mLblRadius,0.2) lHLt.AddRelative(self.mEdtRadius,0.4) lHLt.AddRelative(self.mBtnGlobalRadius,0.4) self.mLytChain.Add(lHLt,20) lHLt = HBoxLayout(FBAttachType.kFBAttachLeft) lHLt.AddRelative(self.mLblPin,0.2) lHLt.AddRelative(self.mBtnPinRoot,0.40) lHLt.AddRelative(self.mBtnPinLeafs,0.40) self.mLytChain.Add(lHLt,20) lHLt = HBoxLayout(FBAttachType.kFBAttachLeft) lHLt.AddRelative(self.mLblExtraParent,0.3) lHLt.AddRelative(self.mCntExtraParent,0.7) self.mLytChain.Add(lHLt,20) self.mLytChain.Add(self.mBtnConstrainSkeleton,20) x = FBAddRegionParam(0,FBAttachType.kFBAttachLeft,"Chain") y = FBAddRegionParam(5,FBAttachType.kFBAttachBottom,"Chain") w = FBAddRegionParam(-5,FBAttachType.kFBAttachRight,"Chain") h = FBAddRegionParam(20,FBAttachType.kFBAttachNone,"") self.AddRegion("GlobalOptions" ,"GlobalOptions" , x, y, w, h) lHLt = HBoxLayout(FBAttachType.kFBAttachLeft) lHLt.AddRelative(self.mLblRB_Prop,0.1) lHLt.AddRelative(self.mCntRB_Prop,0.4) lHLt.AddRelative(self.mLblJ_Prop,0.1) lHLt.AddRelative(self.mCntJ_Prop,0.4) self.SetControl("GlobalOptions" ,lHLt) # Init. def __init__(self): FBTool.__init__(self,gToolName) AddTool(self) self.CreateMembers() self.BuildLayout() self.StartSizeX = 250 self.StartSizeY = 480 # Display if gDevelopment: DestroyToolByName(gToolName) if gToolName in ToolList: tool = ToolList[gToolName] ShowTool(tool) else: tool=PhysicsSpeedupTool() if gDevelopment: ShowTool(tool)