├── README.md ├── functions.py └── animator00.py /README.md: -------------------------------------------------------------------------------- 1 | FOR BLENDER 2.9, PROTOTYPE - This is the NEW coding, concentrated on object oriented principles, using classes. 2 | Currently, this is a step back from the previous coding, but the coding is far better in terms of quality, 3 | understandability, and managability. I am posting this code at this point in case anyone else is interested 4 | in using it, building from it . . . 5 | Coder : Shawn D Irwin (skywola@hotmail.com) 6 | 7 | To run this in Blender, because it is still a prototype, I am running it in the console. 8 | 1. Copy the file animator00.py and paste it into the console 9 | 2. Copy the file functions.py and paste it into the console 10 | 3. Copy the file build.py and paste it into the console 11 | 12 | This will create the skeleton, and animate it in place (speed is not yet set up). 13 | This has most of all the needed code methods that will be needed to set up the animation capability that is expected to be in 14 | the final plugin, that is, when completed, this program will automatically animate a Biped, Quadruped, Bird, or a Spider. 15 | Not only that, in this new version, my intent beyond just making it all object oriented is to make it so an artist can 16 | use components of it to build practically any character they can imagine, because the torso, pelvis, arm, leg, and head 17 | are all separate objects that can work independently! I have not yet included any code for the user interface. 18 | 19 | This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License 20 | as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. 21 | 22 | This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the 23 | implied warranty of MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General 24 | Public License for more details. For a copy of the GNU General Public License, see 25 | http://www.gnu.org/licenses 26 | 27 | When this program is completed, it will allow you to animate a biped, bird, quadruped, centaur, or 28 | a spider very rapidly in Blender. (See www.blender.org) 29 | On completeion of this project, you will be able to click a button to add the bones, parent the 30 | character mesh to the bones, hit the play button, set the speed, and off it will go. 31 | 32 | INSTRUCTIONS FOR BLENDER 2.79: 33 | Run in the console the animator00.py file, then run the build00.py file in the console. Press the 34 | play button, and it will start walking. Note that this is VERY early prototype code, so using 35 | it for an actual animation at this point is probably possible, but not as good as it will be once 36 | the project is finished, there is still a long way to go, still need to add shoulder sway, hip sway, 37 | etc. and to put up the user interface. 38 | 39 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 40 | 41 | When completed, this program will automatically animate a Biped, Quadruped, Bird, Centaur or a Spider . . . in Blender (www.blender.org). This project, (When completed) will allow you to choosing a character type, and it will create the skeleton for the character, skin the character to the skeleton and, when you press the play button the character will walk or run. The quadraped will also hop or gallop. The project will be done via Python, it does not require any fooling with IK, and it has "Stabilization" (it adds bones that allow the character to move freely without major distortions in the character skin), which minimizes having to paint skin weights. 42 | 43 | When created, the bones are in the pose position, and you then attach the character to it, click the activate button, hit PLAY, and the character walks or runs away. Just like that . . . . if you hit rewind, you can re-pose the character. You can make the character walk or run in any direction, or create a crowd of characters, all walking or running in different directions. You can manipulate all the fingers of each hand at once, to open or close the hand or you can control the fingers individually. 44 | 45 | 46 | You can track my progress for this project on Blender Open Artist Group. https://www.linkedin.com/groups/6677523 This is a work in process, so I do upload updates after I create them, you can monitor them. 47 | -------------------------------------------------------------------------------- /functions.py: -------------------------------------------------------------------------------- 1 | # cycle control - this is the engine that creates the movement! 2 | def clock(cycle=1.0, freq=9, amp=.5): # Sets the pace 3 | frame = bpy.context.scene.frame_current 4 | stp = amp * abs((cycle*frame)/freq % 4 - 2) - amp 5 | return round(stp, 2) 6 | 7 | # add to namespace 8 | bpy.app.driver_namespace['clock'] = clock # Important 9 | 10 | def set_pivot(coordinates=Vector()): 11 | bpy.ops.object.mode_set(mode='EDIT') 12 | ob = bpy.context.active_object 13 | mw = ob.matrix_world 14 | o = mw.inverted() @ Vector(coordinates) 15 | ob.data.transform(Matrix.Translation(-o)) 16 | mw.translation = coordinates 17 | bpy.ops.object.mode_set(mode='OBJECT') 18 | 19 | # getEuler output represents: 20 | # bpy.data.objects['rg00biped'].pose.bones["backCenter"] 21 | def getEuler(str_bone_name): # *** Switching to pose mode must be external 22 | ob = bpy.context.object 23 | bone = ob.pose.bones[str_bone_name] 24 | bone.rotation_mode = 'XYZ' 25 | return bone 26 | 27 | def deselectAll(): 28 | for obj in bpy.context.selected_objects: 29 | obj.select_set(False) 30 | 31 | def deleteAll(): 32 | bpy.ops.object.mode_set(mode='OBJECT') 33 | bpy.ops.object.select_all(action='SELECT') 34 | bpy.ops.object.delete() 35 | 36 | # vector 37 | # string 38 | def boneExtrude(vector, name): 39 | bpy.ops.object.mode_set(mode='EDIT') 40 | bpy.ops.armature.extrude_forked(TRANSFORM_OT_translate={"value":vector}) 41 | bpy.context.active_bone.name = name 42 | bone = bpy.context.active_bone 43 | return bone 44 | 45 | def getSceneObjectNumber(): 46 | n = 0 47 | for o in bpy.data.objects: 48 | if("at" in o.name): 49 | n += 1 50 | return n 51 | 52 | def new_armature(name, x=0, y=0, z=0): 53 | bpy.context.scene.frame_start = 0 54 | n = getSceneObjectNumber() 55 | armature = bpy.data.armatures.new(name + str(n) + '_at') # at = Armature 56 | rig = bpy.data.objects.new(name, armature) # rig = Armature object 57 | rig.show_in_front = True 58 | rig.location = (x, y, z) # Set armature point locatioon 59 | # Link to scene 60 | coll = bpy.context.view_layer.active_layer_collection.collection 61 | coll.objects.link(rig) 62 | bpy.context.view_layer.objects.active = rig 63 | bpy.context.view_layer.update() 64 | return rig 65 | 66 | # Make bone creation easy 67 | ''' 68 | def createBone(name="boneName", pHead=Vector(), pTail=Vector(), roll=0, con=False): 69 | bpy.ops.object.mode_set(mode='EDIT') 70 | bData = bpy.context.active_object.data 71 | bone = bData.edit_bones.new(name) 72 | bone.head[:] = [pHead.x, pHead.y, pHead.z] 73 | bone.tail[:] = [pTail.x, pTail.y, pTail.z] 74 | bone.roll = roll 75 | bone.use_connect = con 76 | return bone 77 | ''' 78 | 79 | # Different data paths are used to access different bone data - 80 | # obj = bpy.data.objects['Armature'] 81 | # obj.data.edit_bones # adding, deleting, positioning bones 82 | # obj.data.bones # adjusting bone properties 83 | # obj.pose.bones # adding constraints, custom shapes... 84 | 85 | def createBone(name, head, tail): 86 | bpy.ops.object.mode_set(mode='EDIT', toggle=False) 87 | obArm = bpy.context.active_object 88 | ebs = obArm.data.edit_bones 89 | eb = ebs.new(name) 90 | eb.head = head 91 | eb.tail = tail 92 | return eb 93 | 94 | # Set Driver For Single Axis Only: 95 | def setAxisDriver(euler, fn="0", axis=0, movementType='rotation_euler'): 96 | edriver = euler.driver_add(movementType, axis) 97 | edriver.driver.type = 'SCRIPTED' 98 | edriver.driver.expression = fn 99 | return edriver 100 | 101 | def setActiveArmature(classBone, deselect=True): 102 | bpy.ops.object.mode_set(mode='OBJECT') 103 | if(deselect): 104 | bpy.ops.object.select_all(action='DESELECT') 105 | bpy.context.view_layer.objects.active = classBone.armature 106 | bpy.data.objects[classBone.armature.name].select_set(True) 107 | 108 | # Right arm will need to be set to 90 in most cases 109 | def dropArm(arm, rot=-90): 110 | bpy.ops.object.mode_set(mode='OBJECT') 111 | deselectAll() 112 | arm.armature.select_set(True) 113 | arm.armature.rotation_euler.x = radians(rot) 114 | 115 | def animateBipedLeg(char, leg, flip=False): 116 | set_pivot((char.location.x, char.location.y, char.leg_height)) 117 | fn = str(leg.rotateRangeFemur) +'*(clock()+'+ str(leg.rotatePositionFemur)+")" + leg.ZeroAtFrame0 118 | if(flip): 119 | fn = "-1*" + fn 120 | bJ1 = leg.bones[0] 121 | Driver1 = setAxisDriver(getEuler(bJ1.name), fn, 2) 122 | # 123 | # Leg Tibia 124 | fn = str(leg.rotateRangeTibia) +'*(clock()+'+ str(leg.rotatePositionTibia)+")" + leg.ZeroAtFrame0 125 | if(flip): 126 | fn = str(leg.rotateRangeTibia) +'*(clock()+'+ str(leg.rotatePositionTibia*-1)+")" + leg.ZeroAtFrame0 127 | fn = "-1*" + fn 128 | bJ3L = leg.bones[2] 129 | Driver3 = setAxisDriver(getEuler(bJ3L.name), fn, 2) 130 | # 131 | # Ankle 132 | fn = str(leg.rotateRangeAnkle) +'*(clock()+'+ str(leg.rotatePositionAnkle)+")" + leg.ZeroAtFrame0 133 | if(flip): 134 | fn = str(leg.rotateRangeAnkle) +'*-1*(clock()+'+ str(leg.rotatePositionAnkle)+")" + leg.ZeroAtFrame0 135 | bJ5 = leg.bones[4] 136 | setAxisDriver(getEuler(bJ5.name), fn, 2) 137 | 138 | 139 | def animateBipedArm(char, arm, flip=False): 140 | set_pivot((char.location.x, char.location.y, ch.shoulder_height)) 141 | # Humerus - Arms rotation 142 | fn = "-(" + str(arm.rotatePositionHumerus)+"+clock()*" + str(arm.rotateRangeHumerus) + ")" + arm.ZeroAtFrame0 143 | aJ1 = arm.bones[0] 144 | setAxisDriver(getEuler(aJ1.name), fn, 2) 145 | # Ulna - Arms rotation 146 | fn = "(-1*" + str(arm.rotatePositionUlna)+"-clock()*" + str(arm.rotateRangeUlna) + ")" + arm.ZeroAtFrame0 147 | if(flip): 148 | fn = "(" + str(armR.rotatePositionUlna)+"-clock()*" + str(armR.rotateRangeUlna) + ")" + arm.ZeroAtFrame0 149 | aJ3 = arm.bones[2] 150 | setAxisDriver(getEuler(aJ3.name), fn, 2) 151 | 152 | def setShoulderSwayFB(char, component, axis=1): # left-right sway movement 153 | bpy.context.view_layer.objects.active = component.armature 154 | fn = "-(asin(clock())* " + str(char.shoulder_FB) + "*.2)" 155 | J1 = component.bones[0] 156 | setAxisDriver(getEuler(J1.name), fn, axis, 'rotation_euler') 157 | 158 | def setShoulderSwayUD(char, component, axis=1): # left-right sway movement 159 | bpy.context.view_layer.objects.active = component.armature 160 | fn = "-(asin(clock())* " + str(char.shoulder_UD) + "*.2)" 161 | J1 = component.bones[0] 162 | setAxisDriver(getEuler(J1.name), fn, axis, 'rotation_euler') 163 | 164 | def setSwayLR(char, component, axis=1): # left-right sway movement 165 | bpy.context.view_layer.objects.active = component.armature 166 | fn = "-(asin(clock())* " + str(char.sway_LR) + "*.2)" 167 | J1 = component.bones[0] 168 | setAxisDriver(getEuler(J1.name), fn, axis, 'rotation_euler') 169 | 170 | def setSwayFB(): # forward - backward sway movement 171 | fn = "-(asin(" + 'clock()' + ")* " + str(ch.sway_FB) + "*.01)" 172 | cJ1 = ch.bones[0] 173 | setAxisDriver(getEuler(cJ1.name), fn, 0, 'rotation_euler') 174 | 175 | def setDirection(ch, dir=0): 176 | bpy.ops.object.mode_set(mode='OBJECT') 177 | bpy.context.view_layer.objects.active = ch.armature 178 | bpy.context.view_layer.objects.active.rotation_euler.z = math.radians(dir) 179 | 180 | 181 | 182 | def setBounce(): # Bounce 183 | fn = "-(asin(clock())*" + str(ch.bounce) + "*.01)" 184 | cJ1 = ch.bones[0] 185 | setAxisDriver(getEuler(cJ1.name), fn, 2, 'location') 186 | 187 | 188 | 189 | ## Body Controls 190 | def update(self, context): 191 | bpy.ops.object.mode_set(mode='POSE') 192 | bpy.context.scene.frame_current = 1 193 | bpy.ops.object.mode_set(mode='OBJECT') 194 | 195 | # ch = getCurrentlySelectedChar(): 196 | 197 | 198 | # Rotate the easy way 199 | def rotate(str_bone_name, rad=0, axis=0): 200 | rad = radians(rad) 201 | bpy.ops.object.mode_set(mode='POSE') 202 | ob = bpy.context.object 203 | if(ob.name.startswith("rg")): # ***Now specific to Character types*** 204 | euler = ob.pose.bones[str_bone_name] 205 | euler.rotation_mode = 'XYZ' 206 | bpy.data.objects[ob.name].pose.bones[str_bone_name].rotation_euler[axis] = rad 207 | 208 | 209 | 210 | def setShoulder(): 211 | shoulder_FB = str(ch.shoulder_FB*.04) 212 | fn = "(asin(clock()) * " + shoulder_FB + ")/3.14" 213 | cJs = ch.bones[5] 214 | setAxisDriver(getEuler(cJs.name), fn, 1) 215 | # Compensate for rotation by r0tating neck and head in opposite directiion, in three parts 216 | fn = "-(asin(clock()) * " + shoulder_FB + "/3)/3.14" 217 | cJs = ch.bones[6] 218 | setAxisDriver(getEuler(cJs.name), fn, 1) 219 | cJs = ch.bones[7] 220 | setAxisDriver(getEuler(cJs.name), fn, 1) 221 | cJs = ch.bones[8] 222 | setAxisDriver(getEuler(cJs.name), fn, 1) 223 | # Shoulder up - down movement 224 | shoulder_UD = str(ch.shoulder_UD*.06) 225 | fn = "-(asin(clock()) * " + shoulder_UD + ")/3.14" 226 | cJs = ch.bones[9] 227 | setAxisDriver(getEuler(cJs.name), fn, 2) 228 | fn = "-(asin(clock()) * " + shoulder_UD + ")/3.14" 229 | cJs = ch.bones[10] 230 | setAxisDriver(getEuler(cJs.name), fn, 2) 231 | 232 | # walk speed control 233 | def setHorizontalSpeed(): 234 | spd = ch.speed 235 | frame = bpy.context.scene.frame_current 236 | spd = frame * .04 * spd 237 | return round(spd, 2) 238 | 239 | # add this function to the namespace 240 | bpy.app.driver_namespace['setHorizontalSpeed'] = setHorizontalSpeed 241 | 242 | 243 | ## LEG controls 244 | def setRun(): 245 | ch.cycle = 4.0 246 | ch.bounce = 1.2 247 | ch.hip_rotate = 2.0 248 | ch.sway_LR = 2.0 249 | ch.sway_FB = 4.0 250 | ch.hip_UD = 3.0 251 | ch.shoulder_FB = 2.0 252 | ch.shoulder_UD = 4.0 253 | ch.Arm_Rotation = 4.0 254 | ch.rotatePositionHumerus = 0.0 255 | ch.rotateRangeHumerus = 1.0 256 | ch.rotatePositionUlna = 0.0 257 | ch.rotateRangeUlna = 1.0 258 | ch.rotatePositionFemur = 0.1 # was genProp. from here down 259 | ch.rotatePositionTibia = -.4 # 1.0 260 | ch.rotatePositionAnkle = 0.1 261 | ch.rotatePositionToe = -.1 262 | ch.rotateRangeFemur = 2.2 263 | ch.rotateRangeTibia = 1.0 # .6 264 | ch.rotateRangeAnkle = 2.2 265 | ch.rotateRangeToe = 1.8 # 2.2 266 | ch.rotateRangeBack = 1.0 # Need calibration 267 | ch.rotateRangeNeck = 1.0 # Need calibration 268 | setCharacterAction(self, context) 269 | bpy.ops.object.mode_set(mode='OBJECT') 270 | 271 | def unSetLegRotation(): 272 | # For each bone remove driver (Alternatively, just reset to zero or delete) 273 | for b in leg.bones: 274 | undo = bpy.data.objects[leg.name].pose.bones[b.name] 275 | undo.driver_remove('rotation_euler', -1) 276 | 277 | def unSetArmRotation(self, context): 278 | for b in arm.bones: 279 | undo = bpy.data.objects[arm.name].pose.bones[b.name] 280 | undo.driver_remove('rotation_euler', -1) 281 | 282 | 283 | def setLegArch(leg): 284 | fn = leg.Leg_Arch * .02 # Leg Arch 285 | lJ1 = leg.bones[0] 286 | setAxisDriver(getEuler(lJ1.name), str(-fn), 1) 287 | setAxisDriver(getEuler(lJ1.name), str(fn), 1) 288 | 289 | def setArms(arm): # TODO This roars slider 290 | UD = math.radians(arm.Arms_UD) 291 | aJ1 = arm.bones[0] 292 | rotate(aJ1.name, UD, 2) 293 | rotate(aJ1.name, -UD, 2) 294 | bpy.context.object.data.bones[aJ1.name].select = True 295 | bpy.context.object.data.bones[aJ1.name].select = True 296 | bpy.ops.object.mode_set(mode='POSE') 297 | 298 | def setArmTwistL(arm): # Should be able to merge this and the fn below it. 299 | LArm_Twist = arm.LArm_Twist * -.1 300 | aJ2 = arm.bones[1] 301 | rotate(aJ2.name, LArm_Twist, 1) 302 | aJ3 = arm.bones[2] 303 | rotate(aJ3.name, LArm_Twist, 1) 304 | aJ4 = arm.bones[3] 305 | rotate(aJ4.name, LArm_Twist, 1) 306 | aJ5 = arm.bones[4] 307 | rotate(aJ5.name, LArm_Twist, 1) 308 | bpy.context.object.data.bones[aJ2.name].select = True 309 | bpy.context.object.data.bones[aJ3.name].select = True 310 | bpy.context.object.data.bones[aJ4.name].select = True 311 | bpy.context.object.data.bones[aJ5.name].select = True 312 | bpy.ops.object.mode_set(mode='POSE') 313 | 314 | def setArmTwistR(self, context): 315 | name = getSelectedCharacterName() 316 | RArm_Twist = ch.RArm_Twist * .1 317 | rotate('armJ2.R', RArm_Twist, 1) 318 | rotate('armJ3.R', RArm_Twist, 1) 319 | rotate('armJ4.R', RArm_Twist, 1) 320 | rotate('armJ5.R', RArm_Twist, 1) 321 | bpy.context.object.data.bones['armJ2.R'].select = True 322 | bpy.context.object.data.bones['armJ3.R'].select = True 323 | bpy.context.object.data.bones['armJ4.R'].select = True 324 | bpy.context.object.data.bones['armJ5.R'].select = True 325 | bpy.ops.object.mode_set(mode='POSE') 326 | 327 | 328 | -------------------------------------------------------------------------------- /animator00.py: -------------------------------------------------------------------------------- 1 | import bpy 2 | from bpy.types import Panel 3 | from bpy.types import Operator 4 | from bpy.types import Menu 5 | import bpy, math 6 | import mathutils 7 | from rna_prop_ui import PropertyPanel 8 | from bpy.props import FloatProperty, BoolProperty, StringProperty 9 | context = bpy.context 10 | from collections import deque 11 | import numpy as np 12 | from mathutils import Vector 13 | 14 | sin = math.sin; cos = math.cos; tan = math.tan 15 | asin = math.asin; acos = math.acos; atan = math.atan 16 | fmod = math.fmod; ceil = math.ceil; floor = math.floor 17 | radians = math.radians 18 | cwmPanel = bpy.context.window_manager # cwmPanel PanelProperty 19 | genProp = bpy.types.WindowManager # genProp General Wm Property 20 | 21 | # Initializations 22 | bpy.context.scene.frame_start = 0 23 | 24 | class Util(): 25 | def __init__(self): 26 | self.character_count = 0 27 | 28 | util = Util() 29 | 30 | class Character(): 31 | def __init__(self, type): 32 | util.character_count +=1 33 | self.type = type 34 | self.number = getSceneObjectNumber() # Critical for initial positioning 35 | self.str_n = str(self.number) 36 | self.name = type + self.str_n 37 | self.obs = [] # for objects attached to char, like legs, arms, etc. 38 | # This is a very special string that produces zero at frame Zero 39 | self.ZeroAtFrame0 = '*(frame * (1/(frame+.0001)))' 40 | # Movement settings 41 | self.cycle = 1.0 42 | self.speed = 0.0 43 | self.bounce = 1.2 44 | self.hip_rotate = 0.0 # 2.0 45 | self.sway_LR = 1.0 46 | self.sway_FB = 1.0 47 | self.hip_UD = 2.0 48 | self.shoulder_FB = 1.2 49 | self.shoulder_UD = 1.0 50 | self.rotateRangeBack = 1.0 51 | self.rotateRangeNeck = 1.0 52 | # 53 | self.z = 1.32 # Character location height, constant 54 | self.y = -.4 * self.number # y-axis Get a non-occupied location for character 55 | mod = fmod(self.number, 2) 56 | self.x = .5 * -self.number - mod 57 | if(mod == 0): 58 | self.x = .5 * self.number - mod 59 | self.location = Vector((self.x,self.y,self.z)) 60 | # Properties for specific character build, initial listing is for biped 61 | self.hip_width = .12 62 | self.leg_left = self.location.y + self.hip_width 63 | self.leg_right = self.location.y -self.hip_width 64 | self.backbone_length = 0.1 65 | self.leg_height = self.location.z - (self.backbone_length * 2) 66 | self.shoulder_width = .3 67 | self.shoulder_left = self.location.y + self.shoulder_width 68 | self.shoulder_right = self.location.y -self.shoulder_width 69 | self.shoulder_height = self.location.z + (self.backbone_length * 3) 70 | if(type == "quadruped"): 71 | self.backbone_length = .14 72 | self.shoulder_width = .2 # shoulder = hip width in this case 73 | # It's a bird! 74 | if(type == "avian"): 75 | self.backbone_length = .09 # Shorter backbones 76 | self.shoulder_width = .12 77 | 78 | 79 | class Torso(): 80 | def __init__(self, char): 81 | location = char.location 82 | self.J1 = None 83 | self.J2 = None 84 | self.J3 = None 85 | self.armature_number = str(getSceneObjectNumber()) 86 | # START BUILD 87 | deselectAll() 88 | # For leg connect hip 89 | self.hipL = Vector((0, char.hip_width, 0)) 90 | self.hipR = Vector((0, -char.hip_width, 0)) 91 | # Relative locations for connections 92 | self.name = 'at_torso' + str(char.number) 93 | self.armature = new_armature(self.name, location.x, location.y, location.z) 94 | bonehead = Vector((0, 0, 0)) # At armature 95 | bonetail = Vector((0,0,char.backbone_length)) 96 | self.J1 = createBone('J1', bonehead, bonetail) 97 | # 98 | # Calculate hip location 99 | hip_point_z = char.backbone_length * 3 100 | hipLocation = Vector((location.x, location.y+char.hip_width, location.z-hip_point_z)) 101 | self.hipLocationL = hipLocation 102 | hipLocation = Vector((location.x, location.y-char.hip_width, location.z-hip_point_z)) 103 | self.hipLocationR = hipLocation 104 | # 105 | # Calculate shoulder location for arms 106 | zloc = location.z + (char.backbone_length * 3) 107 | shoulder = Vector((location.x, location.y+char.shoulder_width, zloc)) 108 | self.shoulderlocationL = shoulder 109 | shoulder = Vector((location.x, -location.y+char.shoulder_width, zloc)) 110 | self.shoulderlocationR = shoulder 111 | # 112 | #self.neckbase_location = [location.x+self.handle_tail, location.y, zloc + .03] 113 | self.neckbase_location = [location.x, location.y, zloc + .03] 114 | # 115 | # Start back build 116 | deselectAll() 117 | self.J2 = boneExtrude([0,0,char.backbone_length], "J2") 118 | self.J3 = boneExtrude([0,0,char.backbone_length], "J3") 119 | # 120 | self.shoulderJ7L = boneExtrude([0,char.shoulder_width,0], "shoulder.L") 121 | self.shoulderJ7L_tail = bpy.context.active_bone.tail # Save location for arm connections 122 | # 123 | bpy.ops.armature.select_all(action='DESELECT') 124 | self.J3.select_tail = True 125 | self.J3.select_head = False 126 | char.shoulder_width = char.shoulder_width * -1 # Other way for right 127 | self.shoulderJ7R = boneExtrude([0,char.shoulder_width,0], "shoulder.R") 128 | self.shoulderJ7R_tail = bpy.context.active_bone.tail # Save location for arm connections 129 | # 130 | bpy.ops.object.mode_set(mode='POSE') 131 | self.bones = [] 132 | for bone in self.armature.pose.bones: 133 | self.bones.append(bone) 134 | 135 | class Pelvis(): 136 | def __init__(self, char): 137 | location = char.location 138 | type = char.type 139 | self.J1 = None 140 | self.J2 = None 141 | self.J3 = None 142 | self.armature_number = str(getSceneObjectNumber()) 143 | # START BUILD 144 | deselectAll() 145 | # Relative locations for connections 146 | self.name = 'at_pelvis' + str(char.number) 147 | self.armature = new_armature(self.name, location.x, location.y, location.z) 148 | bonehead = Vector((0, 0, 0)) # At armature 149 | bonetail = Vector((0,0,-char.backbone_length)) 150 | self.J1 = createBone('J1', bonehead, bonetail) 151 | # Calculate hip location 152 | self.hip_width = .12 153 | hip_point_z = char.backbone_length * 3 154 | hipLocation = Vector((location.x, location.y+self.hip_width, location.z-hip_point_z)) 155 | self.hipLocationL = hipLocation 156 | hipLocation = Vector((location.x, location.y-self.hip_width, location.z-hip_point_z)) 157 | self.hipLocationR = hipLocation 158 | # 159 | # Start back build 160 | deselectAll() 161 | bpy.ops.armature.select_all(action='DESELECT') 162 | self.J1.select_tail = False 163 | self.J1.select_head = True 164 | # Reverse direction of build backbones below (behind) handle 165 | char.backbone_length = char.backbone_length * -1 166 | self.J2 = boneExtrude([0,0,char.backbone_length], "J2") 167 | self.J3 = boneExtrude([0,0,char.backbone_length], "J3") 168 | self.hipL = boneExtrude([0,self.hip_width,0], "hipL") 169 | self.hipL_tail = bpy.context.active_bone.tail # Save location for arm connections 170 | bpy.ops.armature.select_all(action='DESELECT') 171 | self.J3.select_tail = True 172 | self.J3.select_head = False 173 | self.hipR = boneExtrude([0,-self.hip_width,0], "hipR") 174 | self.shoulderJ7R_tail = bpy.context.active_bone.tail # Save location for arm connections 175 | # 176 | self.shouldersupport_number = 0 177 | self.rump_support_number = 0 178 | bpy.ops.armature.select_all(action='DESELECT') 179 | # 180 | bpy.ops.object.mode_set(mode='POSE') 181 | self.bones = [] 182 | for bone in self.armature.pose.bones: 183 | self.bones.append(bone) 184 | 185 | class Leg(): 186 | def __init__(self, char, leftright='left', frontback='front'): 187 | self.str_n = str(char.number) 188 | self.armature_number = str(getSceneObjectNumber()) 189 | self.cycledir = 1 # 1 or -1 to sync with opposite leg 190 | self.cyclephase = 0 # 0.0 - 1.0 Not yet used 191 | # This is a very special string that produces zero at frame Zero 192 | self.ZeroAtFrame0 = '*(frame * (1/(frame+.0001)))' 193 | # 194 | #self.y = .12 # y sets for left or right leg 195 | self.gait = 0 # gait pose=0, walk=1, trot=2, run=3, pace=4 196 | # Defaults for walk 197 | self.rotatePositionFemur = 0.1 198 | self.rotatePositionTibia = .4 199 | self.rotatePositionAnkle = 0.1 200 | self.rotatePositionToe = -.1 201 | # 202 | self.rotateRangeFemur = 1.0 203 | self.rotateRangeTibia = 1.0 204 | self.rotateRangeAnkle = 0.8 205 | self.rotateRangeToe = 1.0 206 | # 207 | side = "L" 208 | if(leftright=='right'): 209 | side = "R" 210 | self.name = 'at_leg' + str(char.number) 211 | # 212 | if((char.type == 'biped') or (char.type == 'quadruped')): 213 | y = char.leg_left 214 | if(side == "R"): 215 | y = char.leg_right 216 | self.armature = new_armature(self.name, char.location.x, y, char.leg_height) 217 | start = Vector((0, 0, 0)) # Start at armature location 218 | J1 = Vector((0, 0, -.32)) # Relative to armature location 219 | if(char.type == 'biped'): 220 | biped = [start, J1, Vector((0, 0, -.24)), Vector((0, 0, -.2)), Vector((0, 0, -.14)), Vector((.18, 0, -.06)), Vector((.08, 0, 0)), Vector((.08, 0, 0)), Vector((-.2, 0, -.01))] 221 | self.J1 = createBone("legJ1" + side, start, J1) 222 | self.J2 = boneExtrude(biped[2], "legJ2" + side) 223 | self.J3 = boneExtrude(biped[3], "legJ3" + side) 224 | self.J4 = boneExtrude(biped[4], "legJ4" + side) 225 | self.J5 = boneExtrude(biped[5], "legJ5" + side) 226 | self.J6 = boneExtrude(biped[6], "legJ6" + side) 227 | bpy.ops.armature.select_all(action='DESELECT') 228 | self.J5.select_tail = True 229 | self.J5.select_head = False 230 | self.J7 = boneExtrude(biped[7], "legJ7" + side) 231 | bpy.ops.armature.select_all(action='DESELECT') 232 | self.J5.select_tail = True # Build heal reinforce 233 | self.J5.select_head = False 234 | self.J8 = boneExtrude(biped[8], "legJ8" + side) 235 | deselectAll() #bpy.ops.armature.select_all(action='DESELECT') 236 | if(char.type == 'quadruped'): 237 | leg = [start, J1, Vector((-.12, 0, -.27)), Vector((.06, 0, -.25)), Vector((.04, 0, -.08)), Vector((.05, 0, -.05)), Vector((.03, 0, -.054)),Vector((.07, 0, -.05))] 238 | if(frontback=='front'): 239 | leg[2] = Vector((0, 0, -.27)) 240 | leg[3] = Vector((0, 0, -.25)) 241 | self.J1 = createBone("legJ1" + side, start, J1) 242 | self.J2 = boneExtrude(leg[2], "legJ2" + side) 243 | self.J3 = boneExtrude(leg[3], "legJ3" + side) 244 | self.J4 = boneExtrude(leg[4], "legJ4" + side) 245 | self.J5 = boneExtrude(leg[5], "legJ5" + side) 246 | # 247 | if(char.type == 'avian'): 248 | # Set initial Armature location 249 | x = char.location.x -.194 250 | y = char.location.y + .18 251 | z = char.location.z -.569 252 | if(leftright == 'right'): 253 | y = char.location.y - .18 254 | self.armature = new_armature(self.name, x,y,z) 255 | birdleg = [Vector((0,0,0)), Vector((.01, 0, -0.12)),Vector((-0.02, 0, -0.12)),Vector((-0.02, 0, -0.12)),Vector((-0.02, 0, -0.12)),Vector((.01, 0, -.1)),Vector((.01, 0, -.1)),Vector((.01, 0, -.1)),Vector((0.003, 0, -.06))] 256 | self.hip = createBone("legJ1" + side, birdleg[0], birdleg[1]) 257 | self.J1 = boneExtrude(birdleg[2], "legJ1" + side) 258 | self.J2 = boneExtrude(birdleg[3], "legJ2" + side) 259 | self.J3 = boneExtrude(birdleg[4], "legJ3" + side) 260 | self.J4 = boneExtrude(birdleg[5], "legJ4" + side) 261 | self.J5 = boneExtrude(birdleg[6], "legJ5" + side) 262 | self.J6 = boneExtrude(birdleg[7], "legJ6" + side) 263 | self.J7 = boneExtrude(birdleg[8], "legJ7" + side) 264 | spur = [Vector((-0.07, -.016, .01)),Vector((-0.07, -.015, 0)),Vector((-0.07, -.015, 0)),Vector((-0.07, -.015, 0))] 265 | if(leftright == 'right'): 266 | spur = [Vector((-0.07, .016, .01)),Vector((-0.07, .015, 0)),Vector((-0.07, .015, 0)),Vector((-0.07, .015, 0))] 267 | self.spurJ1 = boneExtrude(spur.x, "leg_spurJ1") 268 | self.spurJ2 = boneExtrude(spur.y, "leg_spurJ2") 269 | self.spurJ3 = boneExtrude(spur.z, "leg_spurJ3") 270 | self.spurJ4 = boneExtrude(spur[3], "leg_spurJ4") 271 | bpy.ops.armature.select_all(action='DESELECT') 272 | self.J7.select_tail = True 273 | self.toeJ1 = boneExtrude([.07, 0, 0], "leg_toeJ1") # Center toe 274 | self.toeJ2 = boneExtrude([.07, 0, 0], "leg_toeJ2") 275 | self.toeJ3 = boneExtrude([.07, 0, 0], "leg_toeJ3") 276 | self.toeJ4 = boneExtrude([.07, 0, 0], "leg_toeJ4") 277 | bpy.ops.armature.select_all(action='DESELECT') 278 | self.J7.select_tail = True 279 | y = -.0358 280 | if(leftright == 'right'): 281 | y = y * -1 282 | self.toeJ1L = boneExtrude([.066, y, 0], "leg_toeJ1L") 283 | self.toeJ2L = boneExtrude([.066, y, 0], "leg_toeJ2L") 284 | self.toeJ3L = boneExtrude([.066, y, 0], "leg_toeJ3L") 285 | self.toeJ4L = boneExtrude([.066, y, 0], "leg_toeJ4L") 286 | bpy.ops.armature.select_all(action='DESELECT') 287 | self.J7.select_tail = True 288 | y = .0358 289 | if(leftright == 'right'): 290 | y = y * -1 291 | self.toeJ1R = boneExtrude([.066, y, 0], "leg_toeJ1R") 292 | self.toeJ2R = boneExtrude([.066, y, 0], "leg_toeJ2R") 293 | self.toeJ3R = boneExtrude([.066, y, 0], "leg_toeJ3R") 294 | self.toeJ4R = boneExtrude([.066, y, 0], "leg_toeJ4R") 295 | # 296 | bpy.ops.object.mode_set(mode='POSE') 297 | self.bones = [] 298 | for bone in self.armature.pose.bones: 299 | self.bones.append(bone) 300 | 301 | 302 | # creeteBone(name="boneName", VHead=(0, 0, 0), VTail=(.1, 0, .1), roll=0, con=False): 303 | class Arm(): 304 | def __init__(self, char, leftright='left'): 305 | self.str_n = str(char.number) 306 | self.armature_number = str(getSceneObjectNumber()) 307 | self.type = type 308 | self.leftright = leftright 309 | self.armature = None 310 | self.cycledir = 1 # 1 or -1 to sync with opposite arm 311 | self.cyclephase = 0 # 0.0 - 1.0 Not yet used 312 | # This is a very special string that produces zero at frame Zero 313 | self.ZeroAtFrame0 = '*(frame * (1/(frame+.0001)))' 314 | # 315 | self.rotatePositionHumerus = 0.0 316 | self.rotateRangeHumerus = 1.0 317 | self.rotatePositionUlna = .24 #0.0 318 | self.rotateRangeUlna = 1.0 319 | # 320 | deselectAll() 321 | side = "L" 322 | x = char.location.x; y = char.shoulder_left; z = char.location.z 323 | if(self.leftright == 'right'): 324 | side = "R" 325 | y = char.shoulder_right 326 | self.name = 'at_arm' + str(char.number) 327 | self.armature = new_armature(self.name, char.location.x, y, char.shoulder_height) 328 | start = Vector((0, 0, 0)) # Start at armature location 329 | J1 = Vector((0, .2, 0)) # Relative to armature location # [.3, .1, .5],[.3, .22, .5] 330 | arm = [start, J1,Vector((0, .2, 0)),Vector((0, .08, 0)),Vector((0, .1, 0)), 331 | Vector((0, .1, 0)),Vector((0, .098, 0)),Vector((0, .05, 0)),Vector((0, .044, 0)),Vector((0, .02, 0)), # MiddleJ1-4 332 | Vector((.03, .098, -.006)),Vector((.011, .032, 0)),Vector((.01, .024, 0)),Vector((.008, .02, 0)), # IndexJ1-4 333 | Vector((-.02, .098, -.006)),Vector((-.01, .042, 0)),Vector((-.007, .032, 0)),Vector((-.004, .02, 0)), # RingJ1-4 334 | Vector((-.046, .095, -.006)),Vector((-.016, .024, 0)),Vector((-.012, .02, 0)),Vector((-.01, .02, 0)), # PinkyJ1-4 335 | Vector((.008, .002, 0)),Vector((.044, .038, -0.01)),Vector((.02, .032, -0.006)),Vector((.01, .02, 0))] # ThumbJ1-4 336 | # 337 | if(self.leftright == 'right'): 338 | for coord in arm: # Right arm has to grow in the opposite direction 339 | coord.y = coord.y * -1 340 | self.J1 = createBone("armJ1" + side, start, J1) 341 | self.J2 = boneExtrude([arm[2].x,arm[2].y,arm[2].z], "armJ2") 342 | self.J3 = boneExtrude([arm[3].x,arm[3].y,arm[3].z], "armJ3") 343 | self.J4 = boneExtrude([arm[4].x,arm[4].y,arm[4].z], "armJ4") 344 | self.J5 = boneExtrude([arm[5].x,arm[5].y,arm[5].z], "armJ5") 345 | self.J6 = boneExtrude([arm[6].x,arm[6].y,arm[6].z], "armJ6") 346 | self.J7 = boneExtrude([arm[7].x,arm[7].y,arm[7].z], "middleJ7") 347 | self.J8 = boneExtrude([arm[8].x,arm[8].y,arm[8].z], "middleJ8") 348 | self.J9 = boneExtrude([arm[9].x,arm[9].y,arm[9].z], "middleJ9") 349 | bpy.ops.armature.select_all(action='DESELECT') 350 | self.J5.select_tail = True 351 | self.J5.select_head = False 352 | self.IJ1 = boneExtrude([arm[10].x,arm[10].y,arm[10].z], "indexJ1") 353 | self.IJ2 = boneExtrude([arm[11].x,arm[11].y,arm[11].z], "indexJ2") 354 | self.IJ3 = boneExtrude([arm[12].x,arm[12].y,arm[12].z], "indexJ3") 355 | self.IJ4 = boneExtrude([arm[13].x,arm[13].y,arm[13].z], "indexJ4") 356 | bpy.ops.armature.select_all(action='DESELECT') 357 | self.J5.select_tail = True 358 | self.J5.select_head = False 359 | self.RJ1 = boneExtrude([arm[14].x,arm[14].y,arm[14].z], "ringJ1") 360 | self.RJ2 = boneExtrude([arm[15].x,arm[15].y,arm[15].z], "ringJ2") 361 | self.RJ3 = boneExtrude([arm[16].x,arm[16].y,arm[16].z], "ringJ3") 362 | self.RJ4 = boneExtrude([arm[17].x,arm[17].y,arm[17].z], "ringJ4") 363 | bpy.ops.armature.select_all(action='DESELECT') 364 | self.J5.select_tail = True 365 | self.J5.select_head = False 366 | self.PJ1 = boneExtrude([arm[18].x,arm[18].y,arm[18].z], "pinkyJ1") 367 | self.PJ2 = boneExtrude([arm[19].x,arm[19].y,arm[19].z], "pinkyJ2") 368 | self.PJ3 = boneExtrude([arm[20].x,arm[20].y,arm[20].z], "pinkyJ3") 369 | self.PJ4 = boneExtrude([arm[21].x,arm[21].y,arm[21].z], "pinkyJ4") 370 | bpy.ops.armature.select_all(action='DESELECT') 371 | self.J5.select_tail = True 372 | self.J5.select_head = False 373 | self.TJ1 = boneExtrude([arm[22].x,arm[22].y,arm[22].z], "thumbJ1") 374 | self.TJ2 = boneExtrude([arm[23].x,arm[23].y,arm[23].z], "thumbJ2") 375 | self.TJ3 = boneExtrude([arm[24].x,arm[24].y,arm[24].z], "thumbJ3") 376 | self.TJ4 = boneExtrude([arm[25].x,arm[25].y,arm[25].z], "thumbJ4") 377 | # 378 | bpy.ops.object.mode_set(mode='POSE') 379 | self.bones = [] 380 | for bone in self.armature.pose.bones: 381 | self.bones.append(bone) 382 | # 383 | deselectAll() 384 | 385 | # Head and neck are considered one unit 386 | class Head(): 387 | def __init__(self, char): 388 | if(bpy.context.mode != 'OBJECT'): 389 | bpy.ops.object.mode_set(mode='OBJECT') 390 | self.str_n = str(char.number) 391 | self.armature_number = str(getSceneObjectNumber()) 392 | self.type = char.type 393 | self.headbase = "" 394 | self.location = char.location 395 | self.cycledir = 1 # 1 or -1 to sync with opposite arm 396 | self.cyclephase = 0 # 0.0 - 1.0 Not yet used 397 | # This is a very special string that produces zero at frame Zero 398 | self.ZeroAtFrame0 = '*(frame * (1/(frame+.0001)))' 399 | # 400 | deselectAll() 401 | self.name = 'at_head' + str(char.number) 402 | if(("biped" in self.type) or ("quadruped" in self.type)): 403 | y = char.location.y 404 | self.armature = new_armature(self.name, char.location.x, y, char.shoulder_height) 405 | # 406 | start = Vector((0, 0, 0)) # Start at armature location 407 | J1 = Vector((0, 0, .12)) # Relative to armature location # [.3, 0, .5],[.3, 0, .54], 408 | head = [start, J1,Vector((.01, 0, .03)),Vector((.01, 0, .03)),Vector((0, 0, .024)), 409 | Vector((0, 0, .09)),Vector((.12, 0, .0)), Vector((.02, 0, -.02)),Vector((0, 0, .04)),Vector((-.05, 0, 0)), 410 | Vector((.08, 0, .09)),Vector((.1, .03, 0)),Vector((.03, 0, 0)), Vector((.1, -.03, 0)),Vector((.03, 0, 0)), 411 | Vector((.02, 0, .04)),Vector((.04, .05, 0)),Vector((.07, -.04, 0)),Vector((.04, -.05, 0)),Vector((.07, .04, 0)), 412 | Vector((.02, 0, 0)),Vector((.04, .05, 0)),Vector((.07, -.04, 0)),Vector((.04, -.05, 0)),Vector((.07, .04, 0))] 413 | # 414 | if("quadruped" in self.type): 415 | head.x = start 416 | head[1] = Vector((.22, 0, .18)) # non-relative 417 | head[2] = Vector((.12, 0, .12)) 418 | head[3] = Vector((.12, 0, .12)) 419 | if(("biped" in self.type) or ("quadruped" in self.type)): 420 | self.J1 = createBone("neckJ1", start, head[2]) 421 | self.J2 = boneExtrude(head[2], "neckJ2") 422 | self.J3 = boneExtrude(head[3], "neckJ3") 423 | self.J4 = boneExtrude(head[4], "headJ4") 424 | self.J5 = boneExtrude(head[5], "headJ5") 425 | bpy.ops.armature.select_all(action='DESELECT') 426 | self.J5.select_tail = True 427 | self.J5.select_head = False 428 | self.J6 = boneExtrude(head[6], "headJ6") 429 | self.J7 = boneExtrude(head[7], "noseJ7") 430 | bpy.ops.armature.select_all(action='DESELECT') 431 | self.J5.select_tail = True 432 | self.J5.select_head = False 433 | self.J8 = boneExtrude(head[8], "headJ8") 434 | self.J9 = boneExtrude(head[9], "headJ9") 435 | self.J10 = boneExtrude(head[10], "headJ10") 436 | bpy.ops.armature.select_all(action='DESELECT') 437 | self.J8.select_tail = True 438 | self.J8.select_head = False 439 | self.J11 = boneExtrude(head[11], "headJ11") 440 | self.J12 = boneExtrude(head[12], "eyeJ12") 441 | bpy.ops.armature.select_all(action='DESELECT') 442 | self.J8.select_tail = True 443 | self.J8.select_head = False 444 | self.J13 = boneExtrude(head[13], "headJ13") 445 | self.J14 = boneExtrude(head[14], "eyeJ14") 446 | bpy.ops.armature.select_all(action='DESELECT') 447 | self.J4.select_tail = True 448 | self.J4.select_head = False 449 | # Upper Jaw L 450 | self.J15 = boneExtrude(head[15], "headJ15") 451 | self.J16 = boneExtrude(head[16], "headJ16") 452 | self.J17 = boneExtrude(head[17], "headJ17") 453 | bpy.ops.armature.select_all(action='DESELECT') 454 | self.J15.select_tail = True 455 | self.J15.select_head = False 456 | # Upper Jaw R 457 | self.J18 = boneExtrude(head[18], "headJ18") 458 | self.J19 = boneExtrude(head[19], "headJ19") 459 | bpy.ops.armature.select_all(action='DESELECT') 460 | self.J4.select_tail = True 461 | self.J4.select_head = False 462 | # Upper Jaw L 463 | self.J20 = boneExtrude(head[20], "headJ20") 464 | self.J21 = boneExtrude(head[21], "jawBaseJ21") 465 | self.J22 = boneExtrude(head[22], "jawJ22") 466 | bpy.ops.armature.select_all(action='DESELECT') 467 | self.J20.select_tail = True 468 | self.J20.select_head = False 469 | # Upper Jaw R 470 | self.J23 = boneExtrude(head[23], "jawBaseJ23") 471 | self.J24 = boneExtrude(head[24], "jawJ24") 472 | bpy.ops.armature.select_all(action='DESELECT') 473 | # 474 | # 475 | if("avian" in self.type): 476 | deselectAll() 477 | x = xyz.x + .132 478 | y = xyz.y 479 | z = xyz.z - .382 480 | armature_number = str(getSceneObjectNumber()) 481 | self.armature = new_armature('armature_head' + armature_number, x,y,z) 482 | # 483 | start = [0, 0, 0] 484 | neckbase = [.06,0,.02] 485 | neck = [start, neckbase, [0.06,0,.02],[0.06,0,.02],[0.026,0,.032],[0.020,0,.039],[0,0,.04],[-.03,0,.052],[.16,0,.03],[-.1,0,.07]] 486 | self.neckbase = createBone(start, neckbase, 'neckbase') 487 | self.neckJ1 = boneExtrude(neck.z, "neckJ1") 488 | self.neckJ2 = boneExtrude(neck[3], "neckJ2") 489 | self.neckJ3 = boneExtrude(neck[4], "neckJ3") 490 | self.neckJ4 = boneExtrude(neck[5], "neckJ4") 491 | self.neckJ5 = boneExtrude(neck[6], "neckJ5") 492 | self.neckJ6 = boneExtrude(neck[7], "neckJ6") 493 | self.neckJ7 = boneExtrude(neck[8], "neckJ7") 494 | self.neckJ8 = boneExtrude(neck[9], "neckJ8") 495 | bpy.ops.armature.select_all(action='DESELECT') 496 | self.neckJ5.select_tail = True 497 | jaw = [[.08,0,-.03],[.08,0,.07],[.16,0,0],[.21,0,-.04],[.03,0,-.05],[.11,0,.058],[.13,0,-.031]] 498 | self.jawbase = boneExtrude(jaw.x, "jawbase") 499 | self.beakbasetop = boneExtrude(jaw.y, "beakbasetop") 500 | self.beakbacktop = boneExtrude(jaw.z, "beakbacktop") 501 | self.beakfronttop = boneExtrude(jaw[3], "beakfronttop") 502 | bpy.ops.armature.select_all(action='DESELECT') 503 | self.jawbase.select_tail = True 504 | self.jawconnect = boneExtrude(jaw[4], "jawconnect") 505 | self.basebottom = boneExtrude(jaw[5], "basebottom") 506 | self.basemidbottom = boneExtrude(jaw[6], "basemidbottom") 507 | self.beakbasefront = boneExtrude(jaw[6], "beakbasefront") 508 | bpy.ops.armature.select_all(action='DESELECT') 509 | self.neckJ6.select_tail = True 510 | eyes = [[.095,.05,0],[.02,0,0],[.095,-.05,0]] 511 | self.eyebaseL = boneExtrude(eyes.x, "eyebaseL") 512 | self.eyeL = boneExtrude(eyes.y, "eyeL") 513 | bpy.ops.armature.select_all(action='DESELECT') 514 | self.neckJ6.select_tail = True 515 | self.eyebaseR = boneExtrude(eyes.z, "eyebaseR") 516 | self.eyeR = boneExtrude(eyes.y, "eyeR") 517 | bpy.ops.armature.select_all(action='DESELECT') 518 | # 519 | bpy.ops.object.mode_set(mode='POSE') 520 | self.head_bones = [] 521 | for bone in self.armature.pose.bones: 522 | self.head_bones.append(bone) 523 | # 524 | deselectAll() 525 | 526 | 527 | class Tail(): 528 | def __init__(self, type, xyz): 529 | if(bpy.context.mode != 'OBJECT'): 530 | bpy.ops.object.mode_set(mode='OBJECT') 531 | self.str_n = str(char.number) 532 | self.type = type 533 | self.name = self.type + str(self.n) + 'tail' 534 | self.armature_number = str(getSceneObjectNumber()) 535 | self.xyz = xyz 536 | self.location = xyz 537 | self.location = None 538 | # This is a very special string that produces zero at frame Zero 539 | self.ZeroAtFrame0 = '*(frame * (1/(frame+.0001)))' 540 | # 541 | deselectAll() 542 | x = self.xyz.x - .253 543 | y = self.xyz.y 544 | z = self.xyz.z - .461 545 | self.name = 'at_tail' + str(char.number) 546 | self.armature = new_armature(self.name, x,y,z) 547 | # 548 | start = [0, 0, 0] 549 | tailJ0 = [-.11 , 0, -.05] 550 | tail = [[-0.1, 0, -.04],[-.1, 0, 0],[-.06, 0, 0],[-.08, 0, 0]] 551 | # 552 | self.J0 = createBone(start, tailJ0, "tailJ0") 553 | self.J1 = boneExtrude(tail.x, "tailJ1") 554 | self.J2 = boneExtrude(tail.y, "tailJ2") 555 | self.J3 = boneExtrude(tail.z, "tailJ3") 556 | self.featherC = boneExtrude(tail[3], "tailfeatherC") 557 | bpy.ops.armature.select_all(action='DESELECT') 558 | self.J3.select_tail = True 559 | featherbase = [[0.025, .022, 0],[0.025, -.022, 0]] 560 | self.fb1L = boneExtrude(featherbase.x, "tail_fb1L") 561 | self.fb2L = boneExtrude(featherbase.x, "tail_fb2L") 562 | self.fb3L = boneExtrude(featherbase.x, "tail_fb3L") 563 | self.fb4L = boneExtrude(featherbase.x, "tail_fb4L") 564 | bpy.ops.armature.select_all(action='DESELECT') 565 | self.J3.select_tail = True 566 | self.fb1R = boneExtrude(featherbase.y, "tail_fb1R") 567 | self.fb2R = boneExtrude(featherbase.y, "tail_fb2R") 568 | self.fb3R = boneExtrude(featherbase.y, "tail_fb3R") 569 | self.fb4R = boneExtrude(featherbase.y, "tail_fb4R") 570 | self.feather4R = boneExtrude([-.08, 0, 0], "tailfeather4R") 571 | bpy.ops.armature.select_all(action='DESELECT') 572 | self.fb3R.select_tail = True 573 | self.feather3R = boneExtrude([-.08, 0, 0], "tailfeather3R") 574 | bpy.ops.armature.select_all(action='DESELECT') 575 | self.fb2R.select_tail = True 576 | self.feather2R = boneExtrude([-.08, 0, 0], "tailfeather2R") 577 | bpy.ops.armature.select_all(action='DESELECT') 578 | self.fb1R.select_tail = True 579 | self.feather1R = boneExtrude([-.08, 0, 0], "tailfeather1R") 580 | # 581 | bpy.ops.armature.select_all(action='DESELECT') 582 | self.fb4L.select_tail = True 583 | self.feather4L = boneExtrude([-.08, 0, 0], "tailfeather4L") 584 | bpy.ops.armature.select_all(action='DESELECT') 585 | self.fb3L.select_tail = True 586 | self.feather3L = boneExtrude([-.08, 0, 0], "tailfeather3L") 587 | bpy.ops.armature.select_all(action='DESELECT') 588 | self.fb2L.select_tail = True 589 | self.feather2L = boneExtrude([-.08, 0, 0], "tailfeather2L") 590 | bpy.ops.armature.select_all(action='DESELECT') 591 | self.fb1L.select_tail = True 592 | self.feather1L = boneExtrude([-.08, 0, 0], "tailfeather1L") 593 | bpy.ops.armature.select_all(action='DESELECT') 594 | deselectAll() 595 | 596 | 597 | class Wing(): 598 | def __init__(self, type, xyz, leftright='left', frontback='front'): 599 | self.str_n = str(char.number) 600 | self.armature_number = str(getSceneObjectNumber()) 601 | self.armature = None 602 | self.xyz = xyz 603 | self.location = xyz 604 | self.type = type 605 | self.name = self.type + self.str_n + "_" + leftright + "_" + 'wing' 606 | self.cycledir = 1 # 1 or -1 to sync with opposite wing 607 | self.cyclephase = 0 # 0.0 - 1.0 Not yet used 608 | self.y = .12 # y sets for left or right wing 609 | # This is a very special string that produces zero at frame Zero 610 | self.ZeroAtFrame0 = '*(frame * (1/(frame+.0001)))' 611 | # 612 | deselectAll() 613 | bpy.ops.armature.select_all(action='DESELECT') 614 | # Set initial Armature location 615 | x = self.xyz.x + .132 616 | y = self.xyz.y + .12 617 | z = self.xyz.z - .082 618 | if(leftright == 'right'): 619 | y = self.xyz.y - .12 620 | self.name = 'at_wing' + str(char.number) 621 | self.armature = new_armature(self.name, x,y,z) 622 | wing = [[0,0,0],[0, .036, 0],[0, .03, 0],[0, .02, 0],[0, .08, 0]] 623 | if(leftright == 'right'): 624 | wing = [[0,0,0],[0, -.036, 0],[0, -.03, 0],[0, -.02, 0],[0, -.08, 0]] 625 | self.wingJ0 = createBone(wing.x, wing.y, "wingJ0") 626 | self.wingJ1 = boneExtrude(wing.y, "wingJ1") 627 | self.wingJ2 = boneExtrude(wing.y, "wingJ2") 628 | self.wingJ3 = boneExtrude(wing.z, "wingJ3") 629 | self.wingJ4 = boneExtrude(wing.z, "wingJ4") 630 | self.wingJ5 = boneExtrude(wing.z, "wingJ5") 631 | self.wingJ6 = boneExtrude(wing.z, "wingJ6") 632 | self.wingJ7 = boneExtrude(wing.z, "wingJ7") 633 | self.wingJ8 = boneExtrude(wing.z, "wingJ8") 634 | self.wingJ9 = boneExtrude(wing.z, "wingJ9") 635 | self.wingJ10 = boneExtrude(wing[3], "wingJ10") 636 | self.wingJ11 = boneExtrude(wing[3], "wingJ11") 637 | self.wingJ12 = boneExtrude(wing[3], "wingJ12") 638 | self.wingJ13 = boneExtrude(wing[3], "wingJ13") 639 | self.wingJ14 = boneExtrude(wing[3], "wingJ14") 640 | self.wingJ15 = boneExtrude(wing[4], "wingJ15") 641 | # 642 | # Feathers 643 | feathers = [[-.05, 0, 0],[-.05, .002, 0],[-.05, .004, 0],[-.05, .006, 0],[-.05, .008, 0], 644 | [-.05, .01, 0],[-.05, .012, 0],[-.05, .014, 0],[-.05, .018, 0],[-.05, .022, 0],[-.05, .026, 0], 645 | [-.05, .03, 0],[-.05, .044, 0],[-.04, .06, 0],[-.03, .075, 0]] 646 | if(leftright == 'right'): 647 | for item in feathers: 648 | item.y = item.y * -1 649 | bpy.ops.armature.select_all(action='DESELECT') 650 | self.wingJ0.select_tail = True 651 | self.feather1 = boneExtrude(feathers.x, "feather1") 652 | bpy.ops.armature.select_all(action='DESELECT') 653 | self.wingJ1.select_tail = True 654 | self.feather2 = boneExtrude(feathers.y, "feather2") 655 | bpy.ops.armature.select_all(action='DESELECT') 656 | self.wingJ2.select_tail = True 657 | self.feather3 = boneExtrude(feathers.z, "feather3") 658 | bpy.ops.armature.select_all(action='DESELECT') 659 | self.wingJ3.select_tail = True 660 | self.feather4 = boneExtrude(feathers[3], "feather4") 661 | bpy.ops.armature.select_all(action='DESELECT') 662 | self.wingJ4.select_tail = True 663 | self.feather5 = boneExtrude(feathers[4], "feather5") 664 | bpy.ops.armature.select_all(action='DESELECT') 665 | self.wingJ5.select_tail = True 666 | self.feather6 = boneExtrude(feathers[5], "feather6") 667 | bpy.ops.armature.select_all(action='DESELECT') 668 | self.wingJ6.select_tail = True 669 | self.feather7 = boneExtrude(feathers[6], "feather7") 670 | bpy.ops.armature.select_all(action='DESELECT') 671 | self.wingJ7.select_tail = True 672 | self.feather8 = boneExtrude(feathers[7], "feather8") 673 | bpy.ops.armature.select_all(action='DESELECT') 674 | self.wingJ8.select_tail = True 675 | self.feather9 = boneExtrude(feathers[8], "feather9") 676 | bpy.ops.armature.select_all(action='DESELECT') 677 | self.wingJ9.select_tail = True 678 | self.feather10 = boneExtrude(feathers[9], "feather10") 679 | bpy.ops.armature.select_all(action='DESELECT') 680 | self.wingJ10.select_tail = True 681 | self.feather11 = boneExtrude(feathers[10], "feather11") 682 | bpy.ops.armature.select_all(action='DESELECT') 683 | self.wingJ11.select_tail = True 684 | self.feather12 = boneExtrude(feathers[11], "feather12") 685 | bpy.ops.armature.select_all(action='DESELECT') 686 | self.wingJ12.select_tail = True 687 | self.feather13 = boneExtrude(feathers[12], "feather13") 688 | bpy.ops.armature.select_all(action='DESELECT') 689 | self.wingJ13.select_tail = True 690 | self.feather14 = boneExtrude(feathers[13], "feather14") 691 | bpy.ops.armature.select_all(action='DESELECT') 692 | deselectAll() 693 | 694 | 695 | a = "avian" # AKA bird 696 | b = "biped" # Done 697 | c = "centaur" 698 | q = "quadruped" # Done 699 | s = "spider" 700 | creatures = [a,b,c,q,s] 701 | 702 | # Legs 703 | left = 'left' 704 | right = 'right' 705 | front = 'front' 706 | back = 'back' 707 | 708 | # Tail, Default is bird tail 709 | straight = 'straight' # Straight tail 710 | 711 | 712 | origin = [0,0,0] 713 | # These are roughly the locations near the origin for 714 | # various parts for ad hoc building activities. 715 | head = [.2,0, 1.9] 716 | hip = [.2,.12, 1.04] 717 | shoulder = [.2,.31, 1.88] 718 | 719 | 720 | # Reference for building characters: 721 | ''' 722 | # Biped 723 | char = Character(b) 724 | armL = Arm(b, char.shoulderlocationL, left) 725 | armL = Arm(b, char.shoulderlocationR, right) 726 | legL = Leg(b, char.hipLocationL, left) 727 | legR = Leg(b, char.hipLocationR, right) 728 | head = Head(b, char.neckbase_location) 729 | 730 | # Quadruped 731 | quad = Character(q) 732 | legL = Leg(q, quad.hiplocation_frontL, left) 733 | legR = Leg(q, quad.hiplocation_frontR, right) 734 | legL = Leg(q, quad.hiplocation_backL, left, back) 735 | legL = Leg(q, quad.hiplocation_backR, right, back) 736 | qhead = Head(q, quad.necklocation) 737 | 738 | # Centaur 739 | quad = Character(q) 740 | legL = Leg(q, quad.hiplocation_frontL, left) 741 | legR = Leg(q, quad.hiplocation_frontR, right) 742 | legL = Leg(q, quad.hiplocation_backL, left, back) 743 | legL = Leg(q, quad.hiplocation_backR, right, back) 744 | char = Character(b) 745 | armL = Arm(b, char.shoulderlocationL, left) 746 | armL = Arm(b, char.shoulderlocationR, right) 747 | head = Head(b, char.neckbase_location) 748 | 749 | # Avian - bird 750 | avian = Character(a) 751 | ahead = Head(a, avian.neckbase_location) 752 | xyz = avian.location 753 | legL = Leg(a, xyz, left) 754 | legR = Leg(a, xyz, right) 755 | tail = Tail(a, xyz) 756 | wing = Wing(a, xyz, left) 757 | wing = Wing(a, xyz, right) 758 | ''' 759 | 760 | --------------------------------------------------------------------------------