Skip to content

Instantly share code, notes, and snippets.

@nothke
Created March 23, 2021 21:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nothke/0982c182c629cca17adfa622e093edd8 to your computer and use it in GitHub Desktop.
Save nothke/0982c182c629cca17adfa622e093edd8 to your computer and use it in GitHub Desktop.
bl_info = {
"name": "Hof Vehicle Export",
"category": "Object",
"blender": (2, 80, 0)
}
import bpy
import os
from bpy.props import IntProperty
from bpy.props import StringProperty
# OPERATOR
def get_root_dir():
return os.path.dirname(bpy.data.filepath)
def is_saved():
basedir = os.path.dirname(bpy.data.filepath)
return basedir != None
def find_layer_collection(layerColl, collName):
found = None
if (layerColl.name == collName):
return layerColl
for layer in layerColl.children:
found = find_layer_collection(layer, collName)
if found:
return found
def select_all_in_collection(layerColl):
# select all in collection (and child collections)
objs = layerColl.collection.all_objects
for ob in objs:
ob.select_set(True)
def set_active(obj):
bpy.context.view_layer.objects.active = obj
def select(obj):
obj.select_set(True)
def validate_selected_objects():
# make sure all objects..
for ob in bpy.context.selected_editable_objects:
# ..are meshes,
if ob.type == "EMPTY":
continue
if ob.type != "MESH":
raise Exception("Object " + ob.name + " is of type " + ob.type + ", but only EMPTY and MESH are valid")
# ..have at least 1 material slot,
if not ob.material_slots:
raise Exception("Object " + ob.name + " has no materials!")
# ..have materials assigned to all slots,
for slot in ob.material_slots:
if slot.material is None:
raise Exception(ob.name + " has an empty slot without assigned material")
# ..are not vertexless
#if len(ob.data.vertices) > 0:
#raise Exception("Object " + ob.name + " has no vertices")
# ..don't have more than 65535 vertices
if len(ob.data.vertices) > 65535:
raise Exception("Object " + ob.name + " has more than 65535 vertices")
# EXPORT OPERATOR
class NOTHKE_OT_HoFExportVehicle(bpy.types.Operator):
"""Tooltip"""
bl_idname = "object.hof_export_vehicle"
bl_label = "Export Vehicle"
# Unused
collectionName: StringProperty(default='EXPORT')
filename: StringProperty(default='hof_export')
def execute(self, context):
# Get current file directory
basedir = os.path.dirname(bpy.data.filepath)
if not basedir:
raise Exception("Blend file is not saved")
# Name is current selected collection
name = context.view_layer.active_layer_collection.name
fpath = basedir + '/vehicles/' + name + '/'
lc = bpy.context.view_layer.layer_collection
# Find glass and dummies collections
glassColl = find_layer_collection(lc, name + '_glass')
dummyColl = find_layer_collection(lc, name + '_dummies')
# Check if collections exist
if glassColl is not None:
print('Found glass collection')
else:
raise Exception(name + "_glass collection not found")
if dummyColl is not None:
print('Found dummies collection')
else:
raise Exception(name + "_dummies collection not found")
# 1. Turn off name_dummy and name_glass collections
glassColl.hide_viewport = True
dummyColl.hide_viewport = True
# 2. Select all
bpy.ops.object.select_all(action='SELECT')
# Intermezzo - Validate!
validate_selected_objects()
# 3. Make sure name_body is active
bodyObj = bpy.data.objects[name + '_body']
set_active(bodyObj)
# 4. Save ?
# 5. Bake id map
if bpy.ops.object.bake_id_map is None:
raise Exception('ID Baker not found!')
bpy.ops.object.bake_id_map()
# 6. Remove all material slots
bpy.ops.view3d.materialutilities_remove_all_material_slots(only_active=False)
# 7. Create a new material name_body
bodyMat = bpy.data.materials.new(name + "_body")
bpy.ops.object.material_slot_add()
bodyObj.active_material = bodyMat
# 8 Copy material to others
bpy.ops.view3d.materialutilities_copy_material_to_others()
# 9 Turn on dummies
dummyColl.hide_viewport = False
# 10 Select all
bpy.ops.object.select_all(action='SELECT')
# 11 Export as vehicles/name/name_for_subs.fbx with HoF option
bpy.ops.export_scene.fbx(
filepath = fpath + name + "_for_subs.fbx",
#version = 'BIN7400',
#use_active_collection = True,
use_selection = True,
global_scale = 1,
apply_unit_scale = False,
apply_scale_options = 'FBX_SCALE_UNITS',
object_types = {'EMPTY', 'MESH', 'OTHER'})
# 12 Turn on glass
glassColl.hide_viewport = False
# 13 Turn off dummies
dummyColl.hide_viewport = True
# 13.5 Select all
bpy.ops.object.select_all(action='SELECT')
# 14 Export as name.fbx
bpy.ops.export_scene.fbx(
filepath = fpath + name + ".fbx",
#version = 'BIN7400',
#use_active_collection = True,
use_selection = True,
global_scale = 1,
apply_unit_scale = False,
apply_scale_options = 'FBX_SCALE_UNITS',
object_types = {'EMPTY', 'MESH', 'OTHER'})
# 15 Revert?
print('Finished export to ' + fpath + ' for: ' + name)
return {'FINISHED'}
# UI PANEL
class NOTHKE_PT_HoFExport(bpy.types.Panel):
"""Creates a Panel in the Object properties window"""
bl_label = "HoF Exporter"
bl_idname = "NOTHKE_PT_HoFExport"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI' #'TOOLS'
bl_category = 'HoF'
def draw(self, context):
scene = context.scene
layout = self.layout
# Not using properties for now
#row = layout.row()
#row.prop(scene, 'hofexport_collectionName')
#row = layout.row()
#row.prop(scene, 'hofexport_filename')
collName = context.view_layer.active_layer_collection.name
row = layout.row()
row.label(text = 'SELECTED: ' + collName)
# export button, create operator
row = layout.row()
op = row.operator('object.hof_export_vehicle', text='Bake ID and Export')
# set properties to operator values
op.collectionName = scene.hofexport_collectionName
op.filename = scene.hofexport_filename
row = layout.row()
row.label(text = 'Important:')
row = layout.row()
row.label(text = 'Save before pressing export')
row = layout.row()
row.label(text = 'Revert after export!')
def register():
bpy.utils.register_class(NOTHKE_OT_HoFExportVehicle)
print('operator registered')
# register properties
bpy.types.Scene.hofexport_layer = bpy.props.IntProperty(
name="Layer",
description="Export all objects from this layer",
default = 1)
bpy.types.Scene.hofexport_collectionName = bpy.props.StringProperty(
name="Collection",
description="Export all objects from this collection",
default='EXPORT')
bpy.types.Scene.hofexport_filename = bpy.props.StringProperty(
name="Filename",
description="Filename",
default = 'hof_export')
print('properties registered')
bpy.utils.register_class(NOTHKE_PT_HoFExport)
print('panel registered')
def unregister():
bpy.utils.unregister_class(NOTHKE_PT_HoFExport)
bpy.utils.unregister_class(NOTHKE_OT_HoFExportVehicle)
del bpy.types.Scene.hofexport_layer
del bpy.types.Scene.hofexport_filename
if __name__ == "__main__":
register()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment