Newer
Older
current_armature = current_obj.data
bones = [x for x in current_armature.bones if not x.parent is None]
child_count += len(bones)
for current_obj in blender_armature:
print ("Current Armature Name: " + current_obj.name)
current_armature = current_obj.data
#armature_id = make_armature_bone(current_obj, psk_file, psa_file)
#we dont want children here - only the top level bones of the armature itself
#we will recursively dump the child bones as we dump these bones
"""
bones = [x for x in current_armature.bones if not x.parent is None]
#will ingore this part of the ocde
"""
if len(current_armature.bones) == 0:
raise RuntimeError("Warning add two bones else it will crash the unreal editor.")
if len(current_armature.bones) == 1:
raise RuntimeError("Warning add one more bone else it will crash the unreal editor.")
Campbell Barton
committed
mainbonecount = 0;
for current_bone in current_armature.bones: #list the bone. #note this will list all the bones.
if(current_bone.parent is None):
mainbonecount += 1
print("Main Bone",mainbonecount)
if mainbonecount > 1:
Campbell Barton
committed
#print("Warning there no main bone.")
raise RuntimeError("There too many Main bones. Number main bones:",mainbonecount)
for current_bone in current_armature.bones: #list the bone. #note this will list all the bones.
if(current_bone.parent is None):
parse_bone(current_bone, psk_file, psa_file, 0, 0, current_obj.matrix_local, None)
break
Brendon Murphy
committed
def get_blender_objects(objects, intype):
Brendon Murphy
committed
#strips current extension (if any) from filename and replaces it with extension passed in
def make_filename_ext(filename, extension):
new_filename = ''
extension_index = filename.find('.')
if extension_index == -1:
new_filename = filename + extension
else:
new_filename = filename[0:extension_index] + extension
return new_filename
Brendon Murphy
committed
# returns the quaternion Grassman product a*b
# this is the same as the rotation a(b(x))
# (ie. the same as B*A if A and B are matrices representing
# the rotations described by quaternions a and b)
return mathutils.Quaternion(
a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z,
a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y,
a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x,
a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w)
Brendon Murphy
committed
def parse_animation(blender_scene, blender_armatures, psa_file):
#to do list:
#need to list the action sets
#need to check if there animation
#need to check if animation is has one frame then exit it
print ('\n----- parsing animation -----')
render_data = blender_scene.render
bHaveAction = True
anim_rate = render_data.fps
print("==== Blender Settings ====")
John Phan
committed
print ('Scene: %s Start Frame: %i, End Frame: %i' % (blender_scene.name, blender_scene.frame_start, blender_scene.frame_end))
print ('Frames Per Sec: %i' % anim_rate)
print ("Default FPS: 24" )
cur_frame_index = 0
if (bpy.context.scene.UEActionSetSettings == '1') or (bpy.context.scene.UEActionSetSettings == '2'):
print("Action Set(s) Settings Idx:",bpy.context.scene.UEActionSetSettings)
print("[==== Action list ====]")
print("Number of Action set(s):",len(bpy.data.actions))
for action in bpy.data.actions:#current number action sets
print("+Action Name:",action.name)
John Phan
committed
print("Group Count:",len(action.groups))
#print("Groups:")
#for bone in action.groups:
#print("> Name: ",bone.name)
#print(dir(bone))
Campbell Barton
committed
amatureobject = None #this is the armature set to none
bonenames = [] #bone name of the armature bones list
for arm in blender_armatures:
amatureobject = arm
#print(dir(amatureobject))
collection = amatureobject.myCollectionUEA #collection of the object
print("\n[==== Armature Object ====]")
if amatureobject != None:
print("+Name:",amatureobject.name)
print("+Number of bones:", len(amatureobject.pose.bones),"\n")
for bone in amatureobject.pose.bones:
bonenames.append(bone.name)
for ActionNLA in bpy.data.actions:
FoundAction = True
if bpy.context.scene.UEActionSetSettings == '2':
for c in collection:
if c.name == ActionNLA.name:
if c.mybool == True:
FoundAction = True
else:
FoundAction = False
break
if FoundAction == False:
print("========================================")
print("Skipping Action Set!",ActionNLA.name)
John Phan
committed
print("Action Group Count:", len(ActionNLA.groups))
print("Bone Group Count:", len(amatureobject.pose.bones))
print("========================================")
#break
John Phan
committed
nomatchbone = 0
baction = True
#print("\nChecking actions matching groups with bone names...")
#Check if the bone names matches the action groups names
John Phan
committed
print("=================================")
print("=================================")
for abone in bonenames:
#print("bone name:",abone)
bfound = False
for group in ActionNLA.groups:
#print("name:>>",abone)
if abone == group.name:
nobone += 1
John Phan
committed
bfound = True
John Phan
committed
if bfound == False:
#print("Not Found!:",abone)
nomatchbone += 1
#else:
#print("Found!:",abone)
print("Armature Bones Count:",nobone , " Action Groups Counts:",len(ActionNLA.groups)," Left Out Count:",nomatchbone)
#if the bones are less some missing bones that were added to the action group names than export this
if (nobone <= len(ActionNLA.groups)) and (bpy.context.scene.unrealignoreactionmatchcount == True) :
#print("Action Set match: Pass")
print("Ingore Action groups Count from Armature bones.")
baction = True
#if action groups matches the bones length and names matching the gourps do something
John Phan
committed
elif ((len(ActionNLA.groups) == len(bonenames)) and (nobone == len(ActionNLA.groups))):
John Phan
committed
print("Action Set match: Fail")
if (baction == True) and (FoundAction == True):
arm = amatureobject #set armature object
if not arm.animation_data:
print("======================================")
print("Check Animation Data: None")
print("Armature has no animation, skipping...")
print("======================================")
break
if not arm.animation_data.action:
print("======================================")
print("Check Action: None")
print("Armature has no animation, skipping...")
print("======================================")
break
#print("Last Action Name:",arm.animation_data.action.name)
#print("Set Action Name:",arm.animation_data.action.name)
act = arm.animation_data.action
action_name = act.name
if not len(act.fcurves):
print("//===========================================================")
print("// None bone pose set keys for this action set... skipping...")
print("//===========================================================")
bHaveAction = False
#this deal with action export control
if bHaveAction == True:
#print("------------------------------------")
print("[==== Action Set ====]")
John Phan
committed
#look for min and max frame that current set keys
framemin, framemax = act.frame_range
#print("max frame:",framemax)
start_frame = int(framemin)
end_frame = int(framemax)
scene_frames = range(start_frame, end_frame+1)
frame_count = len(scene_frames)
#===================================================
anim = AnimInfoBinary()
anim.Name = action_name
anim.Group = "" #what is group?
anim.NumRawFrames = frame_count
anim.AnimRate = anim_rate
anim.FirstRawFrame = cur_frame_index
#===================================================
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
print("Frame Key Set Count:",frame_count, "Total Frame:",frame_count)
#print("init action bones...")
unique_bone_indexes = {}
# bone lookup table
bones_lookup = {}
#build bone node for animation keys needed to be set
for bone in arm.data.bones:
bones_lookup[bone.name] = bone
#print("bone name:",bone.name)
frame_count = len(scene_frames)
#print ('Frame Count: %i' % frame_count)
pose_data = arm.pose
#these must be ordered in the order the bones will show up in the PSA file!
ordered_bones = {}
ordered_bones = sorted([(psa_file.UseBone(x.name), x) for x in pose_data.bones], key=operator.itemgetter(0))
#############################
# ORDERED FRAME, BONE
#for frame in scene_frames:
for i in range(frame_count):
frame = scene_frames[i]
#LOUD
#print ("==== outputting frame %i ===" % frame)
if frame_count > i+1:
next_frame = scene_frames[i+1]
#print "This Frame: %i, Next Frame: %i" % (frame, next_frame)
else:
next_frame = -1
#print "This Frame: %i, Next Frame: NONE" % frame
#frame start from 1 as number one from blender
blender_scene.frame_set(frame)
cur_frame_index = cur_frame_index + 1
for bone_data in ordered_bones:
bone_index = bone_data[0]
pose_bone = bone_data[1]
#print("[=====POSE NAME:",pose_bone.name)
#print("LENG >>.",len(bones_lookup))
#just need the total unique bones used, later for this AnimInfoBinary
unique_bone_indexes[bone_index] = bone_index
#LOUD
#print ("-------------------", pose_bone.name)
head = pose_bone.head
posebonemat = mathutils.Matrix(pose_bone.matrix)
#print(dir(posebonemat))
#print("quat",posebonemat)
#
# Error looop action get None in matrix
# looping on each armature give invert and normalize for None
#
if parent_pose != None:
parentposemat = mathutils.Matrix(parent_pose.matrix)
posebonemat = parentposemat.inverted() * posebonemat
head = posebonemat.to_translation()
quat = posebonemat.to_quaternion().normalized()
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
vkey = VQuatAnimKey()
vkey.Position.X = head.x
vkey.Position.Y = head.y
vkey.Position.Z = head.z
if parent_pose != None:
quat = make_fquat(quat)
else:
quat = make_fquat_default(quat)
vkey.Orientation = quat
#print("Head:",head)
#print("Orientation",quat)
#time from now till next frame = diff / framesPerSec
if next_frame >= 0:
diff = next_frame - frame
else:
diff = 1.0
#print ("Diff = ", diff)
vkey.Time = float(diff)/float(anim_rate)
psa_file.AddRawKey(vkey)
#done looping frames
#done looping armatures
#continue adding animInfoBinary counts here
anim.TotalBones = len(unique_bone_indexes)
print("Bones Count:",anim.TotalBones)
anim.TrackTime = float(frame_count) / anim.AnimRate
print("Time Track Frame:",anim.TrackTime)
psa_file.AddAnimation(anim)
print("------------------------------------\n")
else:
print("[==== Action Set ====]")
print("Action Name:",ActionNLA.name)
John Phan
committed
print("Action Group Count:", len(ActionNLA.groups))
print("Bone Group Count:", len(amatureobject.pose.bones))
print("Action set Skip!")
print("------------------------------------\n")
print("[==== Action Set Single Export====]")
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
#list of armature objects
for arm in blender_armatures:
#check if there animation data from armature or something
if not arm.animation_data:
print("======================================")
print("Check Animation Data: None")
print("Armature has no animation, skipping...")
print("======================================")
break
if not arm.animation_data.action:
print("======================================")
print("Check Action: None")
print("Armature has no animation, skipping...")
print("======================================")
break
act = arm.animation_data.action
#print(dir(act))
action_name = act.name
if not len(act.fcurves):
print("//===========================================================")
print("// None bone pose set keys for this action set... skipping...")
print("//===========================================================")
bHaveAction = False
#this deal with action export control
if bHaveAction == True:
print("Action Name:",action_name)
#look for min and max frame that current set keys
framemin, framemax = act.frame_range
#print("max frame:",framemax)
start_frame = int(framemin)
end_frame = int(framemax)
scene_frames = range(start_frame, end_frame+1)
frame_count = len(scene_frames)
#===================================================
anim = AnimInfoBinary()
anim.Name = action_name
anim.Group = "" #what is group?
anim.NumRawFrames = frame_count
anim.AnimRate = anim_rate
anim.FirstRawFrame = cur_frame_index
#===================================================
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
print("Frame Key Set Count:",frame_count, "Total Frame:",frame_count)
#print("init action bones...")
unique_bone_indexes = {}
# bone lookup table
bones_lookup = {}
#build bone node for animation keys needed to be set
for bone in arm.data.bones:
bones_lookup[bone.name] = bone
#print("bone name:",bone.name)
frame_count = len(scene_frames)
#print ('Frame Count: %i' % frame_count)
pose_data = arm.pose
#these must be ordered in the order the bones will show up in the PSA file!
ordered_bones = {}
ordered_bones = sorted([(psa_file.UseBone(x.name), x) for x in pose_data.bones], key=operator.itemgetter(0))
#############################
# ORDERED FRAME, BONE
#for frame in scene_frames:
for i in range(frame_count):
frame = scene_frames[i]
#LOUD
#print ("==== outputting frame %i ===" % frame)
if frame_count > i+1:
next_frame = scene_frames[i+1]
#print "This Frame: %i, Next Frame: %i" % (frame, next_frame)
else:
next_frame = -1
#print "This Frame: %i, Next Frame: NONE" % frame
#frame start from 1 as number one from blender
blender_scene.frame_set(frame)
cur_frame_index = cur_frame_index + 1
for bone_data in ordered_bones:
bone_index = bone_data[0]
pose_bone = bone_data[1]
#print("[=====POSE NAME:",pose_bone.name)
#print("LENG >>.",len(bones_lookup))
#just need the total unique bones used, later for this AnimInfoBinary
unique_bone_indexes[bone_index] = bone_index
#LOUD
#print ("-------------------", pose_bone.name)
head = pose_bone.head
posebonemat = mathutils.Matrix(pose_bone.matrix)
parent_pose = pose_bone.parent
if parent_pose != None:
parentposemat = mathutils.Matrix(parent_pose.matrix)
#blender 2.4X it been flip around with new 2.50 (mat1 * mat2) should now be (mat2 * mat1)
head = posebonemat.to_translation()
vkey = VQuatAnimKey()
vkey.Position.X = head.x
vkey.Position.Y = head.y
vkey.Position.Z = head.z
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
if parent_pose != None:
quat = make_fquat(quat)
else:
quat = make_fquat_default(quat)
vkey.Orientation = quat
#print("Head:",head)
#print("Orientation",quat)
#time from now till next frame = diff / framesPerSec
if next_frame >= 0:
diff = next_frame - frame
else:
diff = 1.0
#print ("Diff = ", diff)
vkey.Time = float(diff)/float(anim_rate)
psa_file.AddRawKey(vkey)
#done looping frames
#done looping armatures
#continue adding animInfoBinary counts here
anim.TotalBones = len(unique_bone_indexes)
print("Bones Count:",anim.TotalBones)
anim.TrackTime = float(frame_count) / anim.AnimRate
print("Time Track Frame:",anim.TrackTime)
psa_file.AddAnimation(anim)
print("---- Action End ----")
print("==== Finish Action Build ====")
def fs_callback(filename, context):
nbone = 0
start_time = time.clock()
print ("========EXPORTING TO UNREAL SKELETAL MESH FORMATS========\r\n")
print("Blender Version:", bpy.app.version[1],"-")
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
psk = PSKFile()
psa = PSAFile()
#sanity check - this should already have the extension, but just in case, we'll give it one if it doesn't
psk_filename = make_filename_ext(filename, '.psk')
#make the psa filename
psa_filename = make_filename_ext(filename, '.psa')
print ('PSK File: ' + psk_filename)
print ('PSA File: ' + psa_filename)
barmature = True
bmesh = True
blender_meshes = []
blender_armature = []
selectmesh = []
selectarmature = []
current_scene = context.scene
cur_frame = current_scene.frame_current #store current frame before we start walking them during animation parse
objects = current_scene.objects
print("Checking object count...")
for next_obj in objects:
if next_obj.type == 'MESH':
blender_meshes.append(next_obj)
if (next_obj.select):
#print("mesh object select")
copymesh = next_obj.copy()
bpy.context.scene.objects.link(copymesh)
selectmesh.append(copymesh)
if next_obj.type == 'ARMATURE':
blender_armature.append(next_obj)
if (next_obj.select):
#print("armature object select")
selectarmature.append(next_obj)
print("Mesh Count:",len(blender_meshes)," Armature Count:",len(blender_armature))
print("====================================")
print("Checking Mesh Condtion(s):")
mesh = blender_meshes[0]
blender_meshes = []
blender_meshes.append(mesh.copy())
#if there more than one mesh and one mesh select add to array
elif (len(blender_meshes) > 1) and (len(selectmesh) == 1):
if selectmesh[0].location.x != 0 and selectmesh[0].location.y != 0 and selectmesh[0].location.z != 0:
exportmessage = "Error, Mesh Object not Center right should be (0,0,0)."
for mesh in selectmesh:#remove object
bpy.context.scene.objects.unlink(mesh)
return
blender_meshes = []
copymesh = selectmesh[0]
blender_meshes.append(copymesh)
elif (len(blender_meshes) > 1) and (len(selectmesh) >= 1):#if there more than one mesh and some area off center check.
#code build check for merge mesh before ops
print("More than one mesh is selected!")
centermesh = []
notcentermesh = []
countm = 0
for countm in range(len(selectmesh)):
#selectmesh[]
if selectmesh[countm].location.x == 0 and selectmesh[countm].location.y == 0 and selectmesh[countm].location.z == 0:
centermesh.append(selectmesh[countm])
else:
notcentermesh.append(selectmesh[countm])
if len(centermesh) > 0:
blender_meshes = []
selectmesh = []
countm = 0
for countm in range(len(centermesh)):
selectmesh.append(centermesh[countm])
for countm in range(len(notcentermesh)):
selectmesh.append(notcentermesh[countm])
blender_meshes.append(meshmerge(selectmesh))
else:
bmesh = False
exportmessage = " - Select Mesh(s) For Export!"
print(" - Select One Mesh Object!")
bmesh = False
print("====================================")
print("Checking Armature Condtion(s):")
if len(blender_armature) == 1:
print(" - One Armature Scene")
elif (len(blender_armature) > 1) and (len(selectarmature) == 1):
print(" - Too Armature Meshes!")
print(" - [Select] One Armature!")
else:
exportmessage = "None Armature! Create One!"
return
if blender_meshes[0].scale.x == 1 and blender_meshes[0].scale.y == 1 and blender_meshes[0].scale.z == 1:
#print("Okay")
bMeshScale = True
elif blender_meshes[0].scale.x != 1 and blender_meshes[0].scale.y != 1 and blender_meshes[0].scale.z != 1:
print("Error, Mesh Object not scale right should be (1,1,1).")
exportmessage = "Error, Mesh Object not scale right should be (1,1,1)."
return
elif blender_meshes[0].location.x == 0 and blender_meshes[0].location.y == 0 and blender_meshes[0].location.z == 0:
return
elif blender_meshes[0].location.x != 0 and blender_meshes[0].location.y != 0 and blender_meshes[0].location.z != 0:
print("Error, Mesh Object not center.",blender_meshes[0].location)
#exportmessage = "Error, Mesh Object not center."
exportmessage = "Error, Mesh Object not center."
return
else:
exportmessage = "Please Select your Meshes that matches that Armature for Export."
return
bArmatureScale = True
bArmatureCenter = True
if blender_armature and blender_armature[0] is not None:
if blender_armature[0].scale.x == 1 and blender_armature[0].scale.y == 1 and blender_armature[0].scale.z == 1:
#print("Okay")
bArmatureScale = True
else:
print("Error, Armature Object not scale right should be (1,1,1).")
exportmessage = "Error, Armature Object not scale right should be (1,1,1)."
bArmatureScale = False
if blender_armature[0].location.x == 0 and blender_armature[0].location.y == 0 and blender_armature[0].location.z == 0:
#print("Okay")
bArmatureCenter = True
else:
print("Error, Armature Object not center.",blender_armature[0].location)
exportmessage = "Error, Armature Object not center."
bArmatureCenter = False
#print("location:",blender_armature[0].location.x)
if (bmesh == False) or (barmature == False) or (bArmatureCenter == False) or (bArmatureScale == False)or (bMeshScale == False) or (bMeshCenter == False):
exportmessage = "Export Fail! Check Log."
print("=================================")
print("= Export Fail! =")
print("=================================")
else:
exportmessage = "Export Finish!"
#print("blender_armature:",dir(blender_armature[0]))
#print(blender_armature[0].scale)
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
try:
#######################
# STEP 1: MESH DUMP
# we build the vertexes, wedges, and faces in here, as well as a vertexgroup lookup table
# for the armature parse
print("//===============================")
print("// STEP 1")
print("//===============================")
parse_meshes(blender_meshes, psk)
except:
context.scene.frame_set(cur_frame) #set frame back to original frame
print ("Exception during Mesh Parse")
raise
try:
#######################
# STEP 2: ARMATURE DUMP
# IMPORTANT: do this AFTER parsing meshes - we need to use the vertex group data from
# the mesh parse in here to generate bone influences
print("//===============================")
print("// STEP 2")
print("//===============================")
parse_armature(blender_armature, psk, psa)
except:
context.scene.frame_set(cur_frame) #set frame back to original frame
print ("Exception during Armature Parse")
raise
try:
#######################
# STEP 3: ANIMATION DUMP
# IMPORTANT: do AFTER parsing bones - we need to do bone lookups in here during animation frames
print("//===============================")
print("// STEP 3")
print("//===============================")
parse_animation(current_scene, blender_armature, psa)
except:
context.scene.frame_set(cur_frame) #set frame back to original frame
print ("Exception during Animation Parse")
raise
# reset current frame
context.scene.frame_set(cur_frame) #set frame back to original frame
##########################
# FILE WRITE
print("//===========================================")
print("// bExportPsk:",bpy.context.scene.unrealexportpsk," bExportPsa:",bpy.context.scene.unrealexportpsa)
print("//===========================================")
if bpy.context.scene.unrealexportpsk == True:
print("Writing Skeleton Mesh Data...")
#RG - dump psk file
psk.PrintOut()
file = open(psk_filename, "wb")
file.write(psk.dump())
file.close()
print ("Successfully Exported File: " + psk_filename)
if bpy.context.scene.unrealexportpsa == True:
print("Writing Animaiton Data...")
#RG - dump psa file
if not psa.IsEmpty():
psa.PrintOut()
file = open(psa_filename, "wb")
file.write(psa.dump())
file.close()
print ("Successfully Exported File: " + psa_filename)
else:
print ("No Animations (.psa file) to Export")
print ('PSK/PSA Export Script finished in %.2f seconds' % (time.clock() - start_time))
print( "Current Script version: ",bl_info['version'])
#MSG BOX EXPORT COMPLETE
#...
#DONE
print ("PSK/PSA Export Complete")
Brendon Murphy
committed
def write_data(path, context):
print("//============================")
print("// running psk/psa export...")
print("//============================")
fs_callback(path, context)
pass
Brendon Murphy
committed
from bpy.props import *
bpy.types.Scene.unrealfpsrate = IntProperty(
description="Set the frame per second (fps) for unreal",
bpy.types.Scene.unrealexport_settings = EnumProperty(
description="Select a export settings (psk/psa/all)",
items = [("0","PSK","Export PSK"),
("1","PSA","Export PSA"),
("2","ALL","Export ALL")],
default = '0')
bpy.types.Scene.UEActionSetSettings = EnumProperty(
name="Action Set(s) Export Type",
description="For Exporting Single, All, and Select Action Set(s)",
items = [("0","Single","Single Action Set Export"),
("1","All","All Action Sets Export"),
("2","Select","Select Action Set(s) Export")],
default = '0')
bpy.types.Scene.unrealtriangulatebool = BoolProperty(
description="Convert Quad to Tri Mesh Boolean",
John Phan
committed
bpy.types.Scene.unrealignoreactionmatchcount = BoolProperty(
name="Acion Group Ignore Count",
description="It will ingore Action group count as long is matches the " \
"Armature bone count to match and over ride the armature " \
"animation data",
John Phan
committed
default=False)
bpy.types.Scene.unrealdisplayactionsets = BoolProperty(
name="Show Action Set(s)",
description="Display Action Sets Information",
bpy.types.Scene.unrealexportpsk = BoolProperty(
name="bool export psa",
description="bool for exporting this psk format",
default=True)
bpy.types.Scene.unrealexportpsa = BoolProperty(
name="bool export psa",
description="bool for exporting this psa format",
default=True)
bpy.types.Scene.limituv = BoolProperty(
name="bool limit UV",
description="limit UV co-ordinates to [0-1]",
default=False)
class UEAPropertyGroup(bpy.types.PropertyGroup):
## create Properties for the collection entries:
mystring = bpy.props.StringProperty()
mybool = bpy.props.BoolProperty(
name="Export",
description="Check if you want to export the action set",
default = False)
bpy.utils.register_class(UEAPropertyGroup)
## create CollectionProperty and link it to the property class
bpy.types.Object.myCollectionUEA = bpy.props.CollectionProperty(type = UEAPropertyGroup)
bpy.types.Object.myCollectionUEA_index = bpy.props.IntProperty(min = -1, default = -1)
## create operator to add or remove entries to/from the Collection
class OBJECT_OT_add_remove_Collection_Items_UE(bpy.types.Operator):
bl_label = "Add or Remove"
bl_idname = "collection.add_remove_ueactions"
__doc__ = """Button for Add, Remove, Refresh Action Set(s) list"""
set = bpy.props.StringProperty()
def invoke(self, context, event):
obj = context.object
collection = obj.myCollectionUEA
if self.set == "remove":
print("remove")
index = obj.myCollectionUEA_index
collection.remove(index) # This remove on item in the collection list function of index value
if self.set == "add":
print("add")
added = collection.add() # This add at the end of the collection list
added.name = "Action"+ str(random.randrange(0, 101, 2))
if self.set == "refresh":
print("refresh")
ActionNames = []
BoneNames = []
for obj in bpy.data.objects:
if obj.type == 'ARMATURE' and obj.select == True:
print("Armature Name:",obj.name)
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
for bone in obj.pose.bones:
BoneNames.append(bone.name)
break
actionsetmatchcount = 0
for ActionNLA in bpy.data.actions:
nobone = 0
for group in ActionNLA.groups:
for abone in BoneNames:
if abone == group.name:
nobone += 1
break
if (len(ActionNLA.groups) == len(BoneNames)) and (nobone == len(ActionNLA.groups)):
actionsetmatchcount += 1
ActionNames.append(ActionNLA.name)
#print(dir(collection))
#print("collection:",len(collection))
print("action list check")
for action in ActionNames:
BfoundAction = False
#print("action:",action)
for c in collection:
#print(c.name)
if c.name == action:
BfoundAction = True
break
if BfoundAction == False:
added = collection.add() # This add at the end of the collection list
added.name = action
#print("finish...")
return {'FINISHED'}
Brendon Murphy
committed
class ExportUDKAnimData(bpy.types.Operator):
global exportmessage
'''Export Skeleton Mesh / Animation Data file(s)'''
bl_idname = "export_anim.udk" # this is important since its how bpy.ops.export.udk_anim_data is constructed
__doc__ = """One mesh and one armature else select one mesh or armature to be exported"""
# List of operator properties, the attributes will be assigned
# to the class instance from the operator settings before calling.
filepath = StringProperty(
subtype='FILE_PATH',
)
filter_glob = StringProperty(
default="*.psk;*.psa",
options={'HIDDEN'},
)
pskexportbool = BoolProperty(
name="Export PSK",
description="Export Skeletal Mesh",
default= True,
)
psaexportbool = BoolProperty(
name="Export PSA",
description="Export Action Set (Animation Data)",
default= True,
)
actionexportall = BoolProperty(
name="All Actions",
description="This will export all the actions that matches the " \
"current armature",
default=False,
)
ignoreactioncountexportbool = BoolProperty(
name="Ignore Action Group Count",
description="It will ignore action group count but as long it " \
"matches the armature bone count to over ride the " \
"animation data",
default= False,
)
limituvbool = BoolProperty(
name="Limit UV Co-ordinates",
description="Limit UV co-ordinates to [0-1]",
default= False,
)
@classmethod
def poll(cls, context):
return context.active_object != None
def execute(self, context):
#check if skeleton mesh is needed to be exported
if (self.pskexportbool):
bpy.context.scene.unrealexportpsk = True
else:
bpy.context.scene.unrealexportpsk = False
#check if animation data is needed to be exported
if (self.psaexportbool):
bpy.context.scene.unrealexportpsa = True
else:
bpy.context.scene.unrealexportpsa = False
if (self.actionexportall):
bpy.context.scene.UEActionSetSettings = '1'#export one action set
bpy.context.scene.UEActionSetSettings = '0'#export all action sets
John Phan
committed
if(self.ignoreactioncountexportbool):
bpy.context.scene.unrealignoreactionmatchcount = True
else:
bpy.context.scene.unrealignoreactionmatchcount = False
if(self.limituvbool):
bpy.types.Scene.limituv = True
else:
bpy.types.Scene.limituv = False
write_data(self.filepath, context)
self.report({'WARNING', 'INFO'}, exportmessage)
return {'FINISHED'}
def invoke(self, context, event):
wm = context.window_manager
wm.fileselect_add(self)
return {'RUNNING_MODAL'}
Brendon Murphy
committed
class VIEW3D_PT_unrealtools_objectmode(bpy.types.Panel):
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_label = "Unreal Tools"
@classmethod
def poll(cls, context):
return context.active_object
def draw(self, context):
layout = self.layout
rd = context.scene
John Phan
committed
layout.prop(rd, "unrealexport_settings",expand=True)
layout.prop(rd, "UEActionSetSettings")
layout.prop(rd, "unrealignoreactionmatchcount")
#FPS #it use the real data from your scene
layout.prop(rd.render, "fps")
John Phan
committed
layout.operator(OBJECT_OT_UnrealExport.bl_idname)
ArmatureSelect = None
for obj in bpy.data.objects:
Campbell Barton
committed
if obj.type == 'ARMATURE' and obj.select == True:
#print("Armature Name:",obj.name)
ArmatureSelect = obj
break
#display armature actions list
if ArmatureSelect != None and rd.unrealdisplayactionsets == True:
layout.label(("Selected: "+ArmatureSelect.name))
row = layout.row()
row.template_list(obj, "myCollectionUEA", obj, "myCollectionUEA_index") # This show list for the collection
col = row.column(align=True)
col.operator("collection.add_remove_ueactions", icon="ZOOMIN", text="").set = "add" # This show a plus sign button
col.operator("collection.add_remove_ueactions", icon="ZOOMOUT", text="").set = "remove" # This show a minus sign button
col.operator("collection.add_remove_ueactions", icon="FILE_REFRESH", text="").set = "refresh" # This show a refresh sign button
##change name of Entry:
if obj.myCollectionUEA:
entry = obj.myCollectionUEA[obj.myCollectionUEA_index]
layout.prop(entry, "name")
layout.prop(entry, "mybool")
#layout.operator(OBJECT_OT_UTSelectedFaceSmooth.bl_idname)
layout.operator(OBJECT_OT_UTRebuildArmature.bl_idname)
layout.operator(OBJECT_OT_ToggleConsle.bl_idname)
layout.operator(OBJECT_OT_DeleteActionSet.bl_idname)
layout.operator(OBJECT_OT_MeshClearWeights.bl_idname)
Brendon Murphy
committed
class OBJECT_OT_UnrealExport(bpy.types.Operator):
bl_idname = "export_mesh.udk" # XXX, name???
__doc__ = """Select export setting for .psk/.psa or both"""
def invoke(self, context, event):
print("Init Export Script:")
if(int(bpy.context.scene.unrealexport_settings) == 0):
bpy.context.scene.unrealexportpsk = True
bpy.context.scene.unrealexportpsa = False
print("Exporting PSK...")
if(int(bpy.context.scene.unrealexport_settings) == 1):