New Addon: Import Autodesk .max #105013
104
io_import_max.py
104
io_import_max.py
@ -48,6 +48,18 @@ class Import_max(bpy.types.Operator, bpy_extras.io_utils.ImportHelper):
|
||||
filename_ext = ".max"
|
||||
filter_glob: bpy.props.StringProperty(default="*.max", options={'HIDDEN'},)
|
||||
|
||||
scale_objects: bpy.props.FloatProperty(name="Scale",
|
||||
description="Scale factor for all objects",
|
||||
min=0.0, max=10000.0,
|
||||
soft_min=0.0, soft_max=10000.0,
|
||||
default=1.0,
|
||||
)
|
||||
|
||||
use_apply_matrix: bpy.props.BoolProperty(name="Apply Matrix",
|
||||
description="Use matrix to transform the objects",
|
||||
default=True,
|
||||
)
|
||||
|
||||
def execute(self, context):
|
||||
keywords = self.as_keywords(ignore=("axis_forward", "axis_up", "filter_glob"))
|
||||
global_matrix = axis_conversion(from_forward=self.axis_forward, from_up=self.axis_up,).to_4x4()
|
||||
@ -200,6 +212,11 @@ def _clsid(clsid):
|
||||
((i32(clsid, 0), i16(clsid, 4), i16(clsid, 6)) +
|
||||
tuple(map(i8, clsid[8:16]))))
|
||||
|
||||
|
||||
###############
|
||||
# DATA IMPORT #
|
||||
###############
|
||||
|
||||
def is_maxfile (filename):
|
||||
"""Test if file is a MAX OLE2 container."""
|
||||
if hasattr(filename, 'read'):
|
||||
@ -671,6 +688,10 @@ class ImportMaxFile:
|
||||
return data
|
||||
|
||||
|
||||
###################
|
||||
# DATA PROCESSING #
|
||||
###################
|
||||
|
||||
class MaxChunk():
|
||||
"""Representing a chunk of a .max file."""
|
||||
def __init__(self, types, size, level, number):
|
||||
@ -1120,6 +1141,24 @@ def create_matrix(prc):
|
||||
return mtx
|
||||
|
||||
|
||||
def get_matrix_mesh_material(node):
|
||||
refs = get_reference(node)
|
||||
if (refs):
|
||||
mtx = refs.get(0, None)
|
||||
msh = refs.get(1, None)
|
||||
mat = refs.get(3, None)
|
||||
lyr = refs.get(6, None)
|
||||
else:
|
||||
refs = get_references(node)
|
||||
mtx = refs[0]
|
||||
msh = refs[1]
|
||||
mat = refs[3]
|
||||
lyr = None
|
||||
if (len(refs) > 6):
|
||||
lyr = refs[6]
|
||||
return mtx, msh, mat, lyr
|
||||
|
||||
|
||||
def get_property(properties, idx):
|
||||
for child in properties.children:
|
||||
if (child.types & 0x100E):
|
||||
@ -1216,12 +1255,18 @@ def adjust_material(obj, mat):
|
||||
objMaterial.roughness = 1.0 - material.get('shinines', 0.6)
|
||||
|
||||
|
||||
def create_shape(context, pts, indices, node, key, prc, mat):
|
||||
def adjust_matrix(obj, node):
|
||||
mtx = create_matrix(node).flatten()
|
||||
plc = mathutils.Matrix(*mtx)
|
||||
obj.matrix_world = plc
|
||||
return plc
|
||||
|
||||
|
||||
def create_shape(context, pts, indices, node, key, mtx, mat):
|
||||
name = node.get_first(TYP_NAME).data
|
||||
shape = bpy.data.meshes.new(name)
|
||||
if (key is not None):
|
||||
name = "%s_%d" %(name, key)
|
||||
mtx = create_matrix(prc)
|
||||
data = []
|
||||
if (pts):
|
||||
loopstart = []
|
||||
@ -1247,6 +1292,7 @@ def create_shape(context, pts, indices, node, key, prc, mat):
|
||||
obj = bpy.data.objects.new(name, shape)
|
||||
context.view_layer.active_layer_collection.collection.objects.link(obj)
|
||||
adjust_material(obj, mat)
|
||||
obj.matrix_world = mtx
|
||||
return True
|
||||
return True
|
||||
|
||||
@ -1391,31 +1437,6 @@ def create_editable_mesh(context, node, msh, mat, mtx):
|
||||
return created
|
||||
|
||||
|
||||
def get_matrix_mesh_material(node):
|
||||
refs = get_reference(node)
|
||||
if (refs):
|
||||
mtx = refs.get(0, None)
|
||||
msh = refs.get(1, None)
|
||||
mat = refs.get(3, None)
|
||||
lyr = refs.get(6, None)
|
||||
else:
|
||||
refs = get_references(node)
|
||||
mtx = refs[0]
|
||||
msh = refs[1]
|
||||
mat = refs[3]
|
||||
lyr = None
|
||||
if (len(refs) > 6):
|
||||
lyr = refs[6]
|
||||
return mtx, msh, mat, lyr
|
||||
|
||||
|
||||
def adjust_matrix(obj, node):
|
||||
mtx = create_matrix(node).flatten()
|
||||
plc = mathutils.Matrix(*mtx)
|
||||
obj.matrix_world = plc
|
||||
return plc
|
||||
|
||||
|
||||
def create_shell(context, node, shell, mat, mtx):
|
||||
name = node.get_first(TYP_NAME).data
|
||||
refs = get_references(shell)
|
||||
@ -1424,7 +1445,7 @@ def create_shell(context, node, shell, mat, mtx):
|
||||
return created
|
||||
|
||||
|
||||
def create_skipable(context, node, msh, mat, mtx, skip):
|
||||
def create_skipable(context, node, skip):
|
||||
name = node.get_first(TYP_NAME).data
|
||||
print(" skipping %s '%s'... " %(skip, name))
|
||||
return True
|
||||
@ -1443,11 +1464,11 @@ def create_mesh(context, node, msh, mtx, mat):
|
||||
else:
|
||||
skip = SKIPPABLE.get(uid)
|
||||
if (skip is not None):
|
||||
created = create_skipable(context, node, msh, mat, mtx, skip)
|
||||
created = create_skipable(context, node, skip)
|
||||
return created, uid
|
||||
|
||||
|
||||
def create_object(context, node):
|
||||
def create_object(context, node, mscale, transform):
|
||||
parent = get_node_parent(node)
|
||||
node.parent = parent
|
||||
name = get_node_name(node)
|
||||
@ -1458,26 +1479,30 @@ def create_object(context, node):
|
||||
if (parent_mtx):
|
||||
mtx = mtx.dot(parent_mtx)
|
||||
parent = get_node_parent(parent)
|
||||
if (transform):
|
||||
mtx = create_matrix(mtx) @ mscale
|
||||
else:
|
||||
mtx = mscale
|
||||
created, uid = create_mesh(context, node, msh, mtx, mat)
|
||||
|
||||
|
||||
def make_scene(context, parent, level=0):
|
||||
def make_scene(context, mscale, transform, parent, level=0):
|
||||
for chunk in parent.children:
|
||||
if (isinstance(chunk, SceneChunk)):
|
||||
if ((get_guid(chunk) == 0x0001) and (get_super_id(chunk) == 0x0001)):
|
||||
try:
|
||||
create_object(context, chunk)
|
||||
create_object(context, chunk, mscale, transform)
|
||||
except Exception as exc:
|
||||
print('ImportError:', exc, chunk)
|
||||
|
||||
|
||||
def read_scene(context, maxfile, filename):
|
||||
def read_scene(context, maxfile, filename, mscale, transform):
|
||||
global SCENE_LIST
|
||||
SCENE_LIST = read_chunks(maxfile, 'Scene', filename+'.Scn.bin', containerReader=SceneChunk)
|
||||
make_scene(context, SCENE_LIST[0], 0)
|
||||
make_scene(context, mscale, transform, SCENE_LIST[0], 0)
|
||||
|
||||
|
||||
def read(context, filename):
|
||||
def read(context, filename, mscale, transform):
|
||||
if (is_maxfile(filename)):
|
||||
maxfile = ImportMaxFile(filename)
|
||||
prop = maxfile.getproperties('\x05DocumentSummaryInformation', convert_time=True, no_conversion=[10])
|
||||
@ -1487,12 +1512,15 @@ def read(context, filename):
|
||||
read_directory(maxfile, filename)
|
||||
read_class_directory(maxfile, filename)
|
||||
read_video_postqueue(maxfile, filename)
|
||||
read_scene(context, maxfile, filename)
|
||||
read_scene(context, maxfile, filename, mscale, transform)
|
||||
else:
|
||||
print("File seems to be no 3D Studio Max file!")
|
||||
|
||||
|
||||
def load(operator, context, filepath="", global_matrix=None):
|
||||
read(context, filepath)
|
||||
def load(operator, context, filepath="", scale_objects=1.0, use_apply_matrix=False, global_matrix=None):
|
||||
mscale = mathutils.Matrix.Scale(scale_objects, 4)
|
||||
if global_matrix is not None:
|
||||
mscale = global_matrix @ mscale
|
||||
read(context, filepath, mscale, transform=use_apply_matrix)
|
||||
|
||||
return {'FINISHED'}
|
Loading…
Reference in New Issue
Block a user