Hi Loux, I haven't looked into the code itself yet, but one thing that immediately stands out is that it doesn't follow PEP-8 at all. You may want to look into that, as it'll make life easier for people who actually want to review.
Cheers, Sybren On Sat, Sep 09, 2017 at 03:36:58PM +0200, xavier loux wrote: > Hello, I have created an add-ons to easily export content from Blender to > Unreal Engine 4 and I need it to be evaluated and tested to submit it in > Blender. I have attached the .py file (version 0, 1, 1) > > Thank you for your feedback. > With best regards, Loux Xavier > > Add-ons wiki page : > https://wiki.blender.org/index.php/Extensions:2.6/Py/Scripts/Import-Export/Blender_For_UnrealEngine > Submission page : https://developer.blender.org/T52622 > #====================== BEGIN GPL LICENSE BLOCK ============================ > # > # This program is free software: you can redistribute it and/or modify > # it under the terms of the GNU General Public License as published by > # the Free Software Foundation, either version 3 of the License, or > # (at your option) any later version. > # > # This program is distributed in the hope that it will be useful, > # but WITHOUT ANY WARRANTY; without even the implied warranty of > # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > # GNU General Public License for more details. > # > # You should have received a copy of the GNU General Public License > # along with this program. If not, see <http://www.gnu.org/licenses/>. > # All rights reserved. > # > #======================= END GPL LICENSE BLOCK ============================= > > # ---------------------------------------------- > # This addons allows to easily export several objects at the same time in > .fbx > # for use in unreal engine 4 by removing the usual constraints > # while respecting UE4 naming conventions and a clean tree structure. > # It also contains a small toolkit for collisions and sockets > # ---------------------------------------------- > > bl_info = { > 'name': 'Blender for UnrealEngine', > 'description': "This add-ons allows to easily export several objects at > the same time for use in unreal engine 4.", > 'author': 'Loux Xavier (BleuRaven)', > 'version': (0, 1, 1), > 'blender': (2, 78, 0), > 'location': 'View3D > Tool > Unreal Engine 4', > 'warning': '', > "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/" > > "Scripts/Import-Export/Blender_For_UnrealEngine", > 'tracker_url': '', > 'support': 'COMMUNITY', > 'category': 'Import-Export'} > > import os > from mathutils import Vector > from mathutils import Quaternion > import bpy > import fnmatch > from bpy.props import * > from bpy.types import Operator > import math > import mathutils > from bpy import data as bpy_data > > #############################[Variables]############################# > > > exportedAssets = [] #List of exported objects [Assetsype , ExportPath] Reset > with each export > > > #############################[Functions]############################# > > > def GetStringSceneProperty(properties): #Allows to get StringSceneProperty > with properties name. > prop = "" > try: > prop = bpy.context.scene[properties] > return prop > except: > pass > return prop > > > def ChecksRelationship(arrayA, arrayB): #Checks if it exits an identical > variable in two lists > for a in arrayA: > for b in arrayB: > if a == b: > return True > return False > > > def SelectParentAndDesiredChilds(obj): #Selects only all child objects that > must be exported with parent objet > bpy.ops.object.select_all(action='DESELECT') > bpy.context.scene.objects.active = obj > bpy.ops.object.select_grouped(type='CHILDREN_RECURSIVE') > > for unwantedObj in FindAllObjetsByExportType("dont_export"): #Deselect > all objects that should not be exported > unwantedObj.select = False > obj.select = True > > > def ResetArmaturePose(obj): #Reset armature pose > for x in obj.pose.bones: > x.rotation_quaternion = Quaternion((0,0,0),0) > x.scale = Vector((1,1,1)) > x.location = Vector((0,0,0)) > > > def VerifiDirs(directory): #check and create a folder if it does not exist > if not os.path.exists(directory): > os.makedirs(directory) > > > def ExportSingleAnimation(obj, targetAction, dirpath, filename): #Export a > single animation > if obj.type == 'ARMATURE': > bpy.ops.object.mode_set(mode = 'OBJECT') > originalLoc = Vector((0,0,0)) > originalLoc = originalLoc + obj.location #Save objet location > obj.location = (0,0,0) #Moves object to the center of the scene > for export > > SelectParentAndDesiredChilds(obj) > ResetArmaturePose(obj) > > obj.animation_data.action = targetAction #Apply desired action > keyframes = [] > for fcu in obj.animation_data.action.fcurves: > for keyframe in fcu.keyframe_points: > xCurve, yCurve = keyframe.co > keyframes.append(xCurve) > bpy.context.scene.frame_end = keyframes[-1] #Set end_frame on > the final key the current action > VerifiDirs(dirpath) > fullpath = os.path.join( dirpath , filename ) > bpy.ops.export_scene.fbx( > filepath=fullpath, > check_existing=False, > version='BIN7400', > use_selection=True, > object_types={'ARMATURE'}, > bake_anim=True, > bake_anim_use_nla_strips=False, > bake_anim_use_all_actions=False, > bake_anim_force_startend_keying=True, > ) > exportedAssets.append(["Animation", fullpath]) > obj.location = originalLoc #Move object to this saved location > > > def ExportSingleMesh(obj, dirpath, filename): #Export a single Mesh > bpy.ops.object.mode_set(mode = 'OBJECT') > originalLoc = Vector((0,0,0)) > originalLoc = originalLoc + obj.location #Save objet location > obj.location = (0,0,0) #Moves object to the center of the scene for > export > > SelectParentAndDesiredChilds(obj) > > VerifiDirs(dirpath) > fullpath = os.path.join( dirpath , filename ) > bpy.ops.export_scene.fbx(filepath=fullpath, > check_existing=False, > version='BIN7400', > use_selection=True, > bake_anim=False, > ) > meshType = "StaticMesh" > if obj.type == 'ARMATURE': > meshType = "SkeletalMesh" > exportedAssets.append([meshType , fullpath]) > obj.location = originalLoc #Move object to this saved location > > > def FindAllObjetsByExportType(exportType): #Find all objets with a ExportEnum > property desired > targetObj = [] > for obj in bpy.context.scene.objects: > try: > prop = obj.ExportEnum > if prop == exportType: > targetObj.append(obj) > except: > pass > return(targetObj) > > def GenerateUe4Name(name): #From a objet name generate a new name with by > adding a suffix number > > > def IsValidName(testedName): #Checks if an object uses this name. If > not is a valid name > for obj in bpy.context.scene.objects: > if testedName == obj.name: > return False > return True > > > valid = False > number = 0 > newName = "" > while valid == False: > newName = name+"_"+str(number) > if IsValidName(newName): > valid = True > else: > number = number+1 > return newName > > > def ConvertEmptyToUe4Socket(): #Convert all selected empty to unreal socket > if CheckIfCollisionAndSocketOwnerIsValid(): > ownerObjName = GetStringSceneProperty("CollisionAndSocketOwner") > bpy.ops.object.mode_set(mode = 'OBJECT') > ownerObj = bpy.data.objects[ownerObjName] > for obj in bpy.context.selected_objects: > if obj != ownerObj: > if obj.type == 'EMPTY': > obj.name = > GenerateUe4Name("SOCKET_"+ownerObjName) > obj.scale = (0.01,0.01,0.01) > obj.empty_draw_size = 100 > if obj.parent != ownerObj.name: > > bpy.ops.object.select_all(action='DESELECT') > obj.select = True > > bpy.context.scene.objects.active = ownerObj > > bpy.ops.object.parent_set(type='OBJECT', keep_transform=True) > > > def ConvertMeshToUe4Collision(collisionType): #Convert all selected mesh to > unreal collisions > ownerObjName = GetStringSceneProperty("CollisionAndSocketOwner") > if CheckIfCollisionAndSocketOwnerIsValid(): > bpy.ops.object.mode_set(mode = 'OBJECT') > ownerObj = bpy.data.objects[ownerObjName] > prefixName = "" > > #Set the name of the Prefix depending on the type of collision > in agreement with unreal FBX Pipeline > if collisionType == "Box": > prefixName = "UBX_" > elif collisionType == "Capsule": > prefixName = "UCP_" > elif collisionType == "Sphere": > prefixName = "USP_" > elif collisionType == "Convex": > prefixName = "UCX_" > else: > return > > mat = bpy.data.materials.get("UE4Collision") > if mat is None: > mat = bpy.data.materials.new(name="UE4Collision") > mat.diffuse_color = (0, 0.6, 0) > mat.alpha = 0.1 > mat.use_transparency = True > > for obj in bpy.context.selected_objects: > if obj != ownerObj: > if obj.type == 'MESH': > obj.data.materials.clear() > obj.data.materials.append(mat) > > > > obj.name = > GenerateUe4Name(prefixName+ownerObjName) > obj.show_wire = True > obj.show_transparent = True > if obj.parent != ownerObj.name: > > bpy.ops.object.select_all(action='DESELECT') > obj.select = True > > bpy.context.scene.objects.active = ownerObj > > bpy.ops.object.parent_set(type='OBJECT', keep_transform=True) > > > def ExportAllByList(targetObjets): #Export all objects that need to be > exported > if len(targetObjets) > 0: > Scene = bpy.context.scene > blendFileLoc = os.path.dirname(bpy.data.filepath) > smPrefix = GetStringSceneProperty("StaticPrefixExportName") > skPrefix = GetStringSceneProperty("SkeletalPrefixExportName") > animPrefix = GetStringSceneProperty("AnimPrefixExportName") > for obj in targetObjets: > if obj.type == 'ARMATURE': > exportDir = os.path.join( blendFileLoc, > "ExportedFbx" , "SkeletalMesh", obj.name ) > ExportSingleMesh(obj, exportDir, > skPrefix+obj.name+".fbx") > for Action in bpy.data.actions: > > objBonesName = [bone.name for bone in > obj.pose.bones] > animBonesName = > [curve.data_path.split('"')[1] for curve in Action.fcurves] > > if ChecksRelationship(objBonesName, > animBonesName): > print("Il ya une correlation") > animExportDir = os.path.join( > exportDir, "Anim" ) > ExportSingleAnimation(obj, > Action, animExportDir, animPrefix+obj.name+"_"+Action.name+".fbx") > else: > print("Il n'y a pas de > correlation") > else: > exportDir = os.path.join( blendFileLoc, > "ExportedFbx" , "StaticMesh" ) > ExportSingleMesh(obj, exportDir, > smPrefix+obj.name+".fbx") > > def CorrectBadProperty(): > Scene = bpy.context.scene > foo_objs1 = [obj for obj in Scene.objects if > fnmatch.fnmatchcase(obj.name, "UBX*") or > fnmatch.fnmatchcase(obj.name, "UCX*") or > fnmatch.fnmatchcase(obj.name, "UCP*") or > fnmatch.fnmatchcase(obj.name, "USP*") or > fnmatch.fnmatchcase(obj.name, "SOCKET*")] > > for u in foo_objs1: > try: > > if u.ExportEnum == "export_and_childs": > u.ExportEnum = "auto" > except: > pass > > > def ExportComplete(self): #Display a summary at the end of the export and > reset "exportedAssets" > if len(exportedAssets) > 0: > self.report({'INFO'}, "Export of "+str(len(exportedAssets))+" > asset(s) has been finalized ! ") > self.report({'INFO'}, "Look in th console for more info.") > print ("################## Exported asset(s) > ##################") > for asset in exportedAssets: > print (asset[0]+" --> "+asset[1]) > print ("################## Exported asset(s) > ##################") > else: > self.report({'WARNING'}, "Not found assets. with \"Export and > child\" properties.") > self.report({'OPERATOR'}, "Pleas select at least one object and > set \"Export and child\" properties.") > del exportedAssets[:] > > > #############################[Visual and UI]############################# > > #### UI Function > def CheckIfCollisionAndSocketOwnerIsValid(): > for obj in bpy.data.objects: > if GetStringSceneProperty("CollisionAndSocketOwner") == > obj.name: > owner = > bpy.data.objects[GetStringSceneProperty("CollisionAndSocketOwner")] > if owner.type != "ARMATURE": > return True > return False > > #### Propertys > def initObjectProperties(): > bpy.types.Object.ExportEnum = EnumProperty( > name = "Type of export ", > description = "Export type of active object", > items = [("auto", "Auto", "Export only if one parents is \"Export and > child\"", "KEY_HLT", 1), > ("export_and_childs", "Export and childs", "Export self objet > and all childs", "KEYINGSET", 2), > ("dont_export", "Dont export", "Will never export", > "KEY_DEHLT", 3)]) > > > def initSceneProperties(): > bpy.types.Scene.CollisionAndSocketOwner = StringProperty( > name = "Owner", > description = "Enter the owner name of the collision or > socket", > default = "") > > bpy.types.Scene.StaticPrefixExportName = StringProperty( > name = "StaticMesh Prefix", > description = "Prefix of staticMesh when exported", > maxlen = 255, > default = "SM_") > > bpy.types.Scene.SkeletalPrefixExportName = StringProperty( > name = "SkeletalMesh Prefix ", > description = "Prefix of SkeletalMesh when exported", > maxlen = 255, > default = "SK_") > > bpy.types.Scene.AnimPrefixExportName = StringProperty( > name = "AnimationSequence Prefix", > description = "Prefix of AnimationSequence when exported", > maxlen = 255, > default = "Anim_") > return > > > def ChecksProp(prop): > try: > value = prop["StaticPrefixExportName"] > except: > pass > prop["StaticPrefixExportName"] = "SM_" > try: > value = prop["SkeletalPrefixExportName"] > except: > pass > prop["SkeletalPrefixExportName"] = "SK_" > try: > value = prop["AnimPrefixExportName"] > except: > pass > prop["AnimPrefixExportName"] = "Anim_" > > return > > #### Panels > class ue4PropertiesPanel(bpy.types.Panel): #Is Objet Properties panel > bl_idname = "panel.ue4.properties" > bl_label = "Objet Properties" > bl_space_type = "VIEW_3D" > bl_region_type = "TOOLS" > bl_category = "Unreal Engine 4" > > def draw(self, context): > layout = self.layout > try: > ob = context.object > layout.prop(ob, 'ExportEnum') > except: > pass > row = self.layout.row().split(percentage = 0.80 ) > row = row.column() > > row.operator("object.selectexport") > row.operator("object.deselectexport") > > > class ue4CollisionsAndSocketsPanel(bpy.types.Panel): #Is Collisions And > Sockets panel > bl_idname = "panel.ue4.collisionsandsockets" > bl_label = "Collisions And Sockets" > bl_space_type = "VIEW_3D" > bl_region_type = "TOOLS" > bl_category = "Unreal Engine 4" > > def draw(self, context): > > scene = context.scene > layout = self.layout > > ownerSelect = layout.row().split(align=True, percentage=0.9) > ownerSelect.prop_search(scene, "CollisionAndSocketOwner", > scene, "objects") > ownerSelect.operator("object.setownerbyactive", text="", > icon='EYEDROPPER') > > > > layout.label("Convert selected objet to Unreal collision or > socket", icon='PHYSICS') > > convertButtons = layout.row().split(percentage = 0.80 ) > convertButtons.active = CheckIfCollisionAndSocketOwnerIsValid() > convertButtons.enabled = CheckIfCollisionAndSocketOwnerIsValid() > convertButtons = convertButtons.column() > convertButtons.operator("object.converttoboxcollision", > icon='MESH_CUBE') > convertButtons.operator("object.converttoconvexcollision", > icon='MESH_ICOSPHERE') > convertButtons.operator("object.converttocapsulecollision", > icon='MESH_CAPSULE') > convertButtons.operator("object.converttospherecollision", > icon='SOLID') > convertButtons.operator("object.converttosocket", > icon='OUTLINER_DATA_EMPTY') > > class ue4CheckCorrect(bpy.types.Panel): #Is Check and correct panel > bl_idname = "panel.ue4.CheckCorrect" > bl_label = "Check and correct" > bl_space_type = "VIEW_3D" > bl_region_type = "TOOLS" > bl_category = "Unreal Engine 4" > > def draw(self, context): > scn = context.scene > props = self.layout.row().operator("object.correctproperty", > icon='FILE_TICK') > > class ue4ExportPanel(bpy.types.Panel): #Is Export panel > bl_idname = "panel.ue4.export" > bl_label = "Export" > bl_space_type = "VIEW_3D" > bl_region_type = "TOOLS" > bl_category = "Unreal Engine 4" > > def draw(self, context): > scn = context.scene > self.layout.prop(scn, 'StaticPrefixExportName', > icon='OBJECT_DATA') > self.layout.prop(scn, 'SkeletalPrefixExportName', > icon='OBJECT_DATA') > self.layout.prop(scn, 'AnimPrefixExportName', > icon='OBJECT_DATA') > props = self.layout.row().operator("object.exportforunreal", > icon='EXPORT') > > #### Buttons > class SelectExportAndChildButton(bpy.types.Operator): > bl_label = "Select all \"Export and childs\" objects" > bl_idname = "object.selectexport" > bl_description = "Select all root objects that will be exported" > > def execute(self, context): > for obj in FindAllObjetsByExportType("export_and_childs"): > obj.select = True > return {'FINISHED'} > > > class DeselectExportAndChildButton(bpy.types.Operator): > bl_label = "Deselect all \"Export and childs\" objects" > bl_idname = "object.deselectexport" > bl_description = "Deselect all root objects that will be exported" > > def execute(self, context): > for obj in FindAllObjetsByExportType("export_and_childs"): > obj.select = False > return {'FINISHED'} > > class SetOwnerByActive(bpy.types.Operator): > bl_label = "Set owner by active selection" > bl_idname = "object.setownerbyactive" > bl_description = "Set owner by active selection" > > def execute(self, context): > try: > bpy.context.scene["CollisionAndSocketOwner"] = > bpy.context.active_object.name > except: > pass > bpy.context.scene["CollisionAndSocketOwner"] = "" > return {'FINISHED'} > > class ConvertToUECollisionButtonBox(bpy.types.Operator): > bl_label = "Convert to box (UBX)" > bl_idname = "object.converttoboxcollision" > bl_description = "Convert selected mesh(s) to Unreal collision ready > for export (Boxes type)" > > def execute(self, context): > ConvertMeshToUe4Collision("Box") > return {'FINISHED'} > > > class ConvertToUECollisionButtonCapsule(bpy.types.Operator): > bl_label = "Convert to capsule (UCP)" > bl_idname = "object.converttocapsulecollision" > bl_description = "Convert selected mesh(s) to Unreal collision ready > for export (Capsules type)" > > def execute(self, context): > ConvertMeshToUe4Collision("Capsule") > return {'FINISHED'} > > > class ConvertToUECollisionButtonSphere(bpy.types.Operator): > bl_label = "Convert to sphere (USP)" > bl_idname = "object.converttospherecollision" > bl_description = "Convert selected mesh(s) to Unreal collision ready > for export (Spheres type)" > > def execute(self, context): > ConvertMeshToUe4Collision("Sphere") > return {'FINISHED'} > > > class ConvertToUECollisionButtonConvex(bpy.types.Operator): > bl_label = "Convert to convex shape (UCX)" > bl_idname = "object.converttoconvexcollision" > bl_description = "Convert selected mesh(s) to Unreal collision ready > for export (Convex shapes type)" > > def execute(self, context): > ConvertMeshToUe4Collision("Convex") > return {'FINISHED'} > > > class ConvertToUESocketButton(bpy.types.Operator): > bl_label = "Convert to socket (SOCKET)" > bl_idname = "object.converttosocket" > bl_description = "Convert selected empty(s) to Unreal sockets ready for > export" > > def execute(self, context): > ConvertEmptyToUe4Socket() > return {'FINISHED'} > > > class ExportForUnrealEngineButton(bpy.types.Operator): > bl_label = "Export for UnrealEngine 4" > bl_idname = "object.exportforunreal" > bl_description = "Export all objet intended for export in scene to fbx" > > def execute(self, context): > ChecksProp(bpy.context.scene) > ExportAllByList(FindAllObjetsByExportType("export_and_childs")) > ExportComplete(self) > return {'FINISHED'} > > class CorrectBadPropertyButton(bpy.types.Operator): > bl_label = "Correct bad property" > bl_idname = "object.correctproperty" > bl_description = "Corrects bad properties" > > def execute(self, context): > CorrectBadProperty(self) > return {'FINISHED'} > > > #############################[...]############################# > > > def register(): > bpy.utils.register_module(__name__) > bpy.types.Scene.my_prop = bpy.props.StringProperty(default="default > value") > initObjectProperties() > initSceneProperties() > > > def unregister(): > bpy.utils.unregister_module(__name__) > > > if __name__ == "__main__": > register() > _______________________________________________ > Bf-committers mailing list > Bf-committers@blender.org > https://lists.blender.org/mailman/listinfo/bf-committers -- Sybren A. Stüvel https://cloud.blender.org/ https://stuvelfoto.nl/ https://stuvel.eu/
signature.asc
Description: PGP signature
_______________________________________________ Bf-committers mailing list Bf-committers@blender.org https://lists.blender.org/mailman/listinfo/bf-committers