io_scene_3ds: Take scene units into account for export #104775

Merged
Sebastian Sille merged 7 commits from :main into main 2023-07-25 17:06:58 +02:00
3 changed files with 48 additions and 17 deletions

View File

@ -55,9 +55,9 @@ class Import3DS(bpy.types.Operator, ImportHelper):
soft_min=0.0, soft_max=1000.0, soft_min=0.0, soft_max=1000.0,
default=10.0, default=10.0,
) )
convert_measure: BoolProperty( convert_unit: BoolProperty(
name="Convert Measure", name="Convert Units",
description="Convert from millimeters to meters", description="Converts to scene unit length settings",
default=False, default=False,
) )
use_image_search: BoolProperty( use_image_search: BoolProperty(
@ -149,7 +149,7 @@ class MAX3DS_PT_import_transform(bpy.types.Panel):
operator = sfile.active_operator operator = sfile.active_operator
layout.prop(operator, "constrain_size") layout.prop(operator, "constrain_size")
layout.prop(operator, "convert_measure") layout.prop(operator, "convert_unit")
layout.prop(operator, "use_apply_transform") layout.prop(operator, "use_apply_transform")
layout.prop(operator, "use_world_matrix") layout.prop(operator, "use_world_matrix")
layout.prop(operator, "axis_forward") layout.prop(operator, "axis_forward")
@ -176,6 +176,11 @@ class Export3DS(bpy.types.Operator, ExportHelper):
soft_min=0.0, soft_max=100000.0, soft_min=0.0, soft_max=100000.0,
default=1.0, default=1.0,
) )
unit_convert: BoolProperty(
name="Convert Units",
description="Converts to scene unit length settings",
default=False,
)
use_selection: BoolProperty( use_selection: BoolProperty(
name="Selection Only", name="Selection Only",
description="Export selected objects only", description="Export selected objects only",
@ -259,6 +264,7 @@ class MAX3DS_PT_export_transform(bpy.types.Panel):
operator = sfile.active_operator operator = sfile.active_operator
layout.prop(operator, "scale_factor") layout.prop(operator, "scale_factor")
layout.prop(operator, "unit_convert")
layout.prop(operator, "axis_forward") layout.prop(operator, "axis_forward")
layout.prop(operator, "axis_up") layout.prop(operator, "axis_up")

View File

@ -1489,10 +1489,9 @@ def make_ambient_node(world):
# EXPORT # # EXPORT #
########## ##########
def save(operator, context, filepath="", scale_factor=1.0, use_selection=False, use_hierarchy=False, write_keyframe=False, global_matrix=None): def save(operator, context, filepath="", scale_factor=1.0, convert_unit=False,
use_selection=False, use_hierarchy=False, write_keyframe=False, global_matrix=None):
"""Save the Blender scene to a 3ds file.""" """Save the Blender scene to a 3ds file."""
mtx_scale = mathutils.Matrix.Scale(scale_factor, 4)
# Time the export # Time the export
duration = time.time() duration = time.time()
@ -1503,6 +1502,20 @@ def save(operator, context, filepath="", scale_factor=1.0, use_selection=False,
depsgraph = context.evaluated_depsgraph_get() depsgraph = context.evaluated_depsgraph_get()
world = scene.world world = scene.world
unit_measure = 1.0
if unit_convert:
unit_length = sce.unit_settings.length_unit
if unit_length == 'KILOMETERS':
unit_measure = 0.001
elif unit_length == 'CENTIMETERS':
unit_measure = 100
elif unit_length == 'MILLIMETERS':
unit_measure = 1000
elif unit_length == 'MICROMETERS':
unit_measure = 1000000
mtx_scale = mathutils.Matrix.Scale((scale_factor * unit_measure),4)
if global_matrix is None: if global_matrix is None:
global_matrix = mathutils.Matrix() global_matrix = mathutils.Matrix()

View File

@ -1101,8 +1101,8 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI
for keydata in keyframe_data.items(): for keydata in keyframe_data.items():
trackposition[keydata[0]] = keydata[1] # Keep track to position for target calculation trackposition[keydata[0]] = keydata[1] # Keep track to position for target calculation
child.location = apply_constrain(keydata[1]) if hierarchy == ROOT_OBJECT else mathutils.Vector(keydata[1]) child.location = apply_constrain(keydata[1]) if hierarchy == ROOT_OBJECT else mathutils.Vector(keydata[1])
if MEASURE: if MEASURE != 1.0:
child.location = child.location * 0.001 child.location = child.location * MEASURE
if hierarchy == ROOT_OBJECT: if hierarchy == ROOT_OBJECT:
child.location.rotate(CONVERSE) child.location.rotate(CONVERSE)
if not contextTrack_flag & 0x100: # Flag 0x100 unlinks X axis if not contextTrack_flag & 0x100: # Flag 0x100 unlinks X axis
@ -1129,8 +1129,8 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI
scale = mathutils.Vector.Fill(3, (CONSTRAIN * 0.1)) if CONSTRAIN != 0.0 else child.scale scale = mathutils.Vector.Fill(3, (CONSTRAIN * 0.1)) if CONSTRAIN != 0.0 else child.scale
transformation = mathutils.Matrix.LocRotScale(locate, rotate, scale) transformation = mathutils.Matrix.LocRotScale(locate, rotate, scale)
child.matrix_world = transformation child.matrix_world = transformation
if MEASURE: if MEASURE != 1.0:
child.matrix_world = mathutils.Matrix.Scale(0.001,4) @ child.matrix_world child.matrix_world = mathutils.Matrix.Scale(MEASURE,4) @ child.matrix_world
if hierarchy == ROOT_OBJECT: if hierarchy == ROOT_OBJECT:
child.matrix_world = CONVERSE @ child.matrix_world child.matrix_world = CONVERSE @ child.matrix_world
child.keyframe_insert(data_path="rotation_euler", index=0, frame=keydata[0]) child.keyframe_insert(data_path="rotation_euler", index=0, frame=keydata[0])
@ -1305,7 +1305,7 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI
# IMPORT # # IMPORT #
########## ##########
def load_3ds(filepath, context, CONSTRAIN=10.0, MEASURE=False, IMAGE_SEARCH=True, def load_3ds(filepath, context, CONSTRAIN=10.0, UNITS=False, IMAGE_SEARCH=True,
WORLD_MATRIX=False, KEYFRAME=True, APPLY_MATRIX=True, CONVERSE=None): WORLD_MATRIX=False, KEYFRAME=True, APPLY_MATRIX=True, CONVERSE=None):
print("importing 3DS: %r..." % (filepath), end="") print("importing 3DS: %r..." % (filepath), end="")
@ -1313,6 +1313,7 @@ def load_3ds(filepath, context, CONSTRAIN=10.0, MEASURE=False, IMAGE_SEARCH=True
if bpy.ops.object.select_all.poll(): if bpy.ops.object.select_all.poll():
bpy.ops.object.select_all(action='DESELECT') bpy.ops.object.select_all(action='DESELECT')
MEASURE = 1.0
duration = time.time() duration = time.time()
current_chunk = Chunk() current_chunk = Chunk()
file = open(filepath, 'rb') file = open(filepath, 'rb')
@ -1335,6 +1336,17 @@ def load_3ds(filepath, context, CONSTRAIN=10.0, MEASURE=False, IMAGE_SEARCH=True
object_matrix.clear() object_matrix.clear()
scn = context.scene scn = context.scene
if UNITS:
unit_length = sce.unit_settings.length_unit
if unit_length == 'KILOMETERS':
MEASURE = 1000.0
elif unit_length == 'CENTIMETERS':
MEASURE = 0.01
elif unit_length == 'MILLIMETERS':
MEASURE = 0.001
elif unit_length == 'MICROMETERS':
MEASURE = 0.000001
imported_objects = [] # Fill this list with objects imported_objects = [] # Fill this list with objects
process_next_chunk(context, file, current_chunk, imported_objects, CONSTRAIN, process_next_chunk(context, file, current_chunk, imported_objects, CONSTRAIN,
IMAGE_SEARCH, WORLD_MATRIX, KEYFRAME, CONVERSE, MEASURE) IMAGE_SEARCH, WORLD_MATRIX, KEYFRAME, CONVERSE, MEASURE)
@ -1348,8 +1360,8 @@ def load_3ds(filepath, context, CONSTRAIN=10.0, MEASURE=False, IMAGE_SEARCH=True
if ob.type == 'MESH': if ob.type == 'MESH':
ob.data.transform(ob.matrix_local.inverted()) ob.data.transform(ob.matrix_local.inverted())
if MEASURE: if UNITS:
unit_mtx = mathutils.Matrix.Scale(0.001,4) unit_mtx = mathutils.Matrix.Scale(MEASURE,4)
for ob in imported_objects: for ob in imported_objects:
if ob.type == 'MESH': if ob.type == 'MESH':
ob.data.transform(unit_mtx) ob.data.transform(unit_mtx)
@ -1432,13 +1444,13 @@ def load_3ds(filepath, context, CONSTRAIN=10.0, MEASURE=False, IMAGE_SEARCH=True
def load(operator, context, filepath="", constrain_size=0.0, def load(operator, context, filepath="", constrain_size=0.0,
convert_measure=False, use_image_search=True, convert_unit=False, use_image_search=True,
use_world_matrix=False, read_keyframe=True, use_world_matrix=False, read_keyframe=True,
use_apply_transform=True, global_matrix=None, use_apply_transform=True, global_matrix=None,
): ):
load_3ds(filepath, context, CONSTRAIN=constrain_size, load_3ds(filepath, context, CONSTRAIN=constrain_size,
MEASURE=convert_measure, IMAGE_SEARCH=use_image_search, UNITS=convert_unit, IMAGE_SEARCH=use_image_search,
WORLD_MATRIX=use_world_matrix, KEYFRAME=read_keyframe, WORLD_MATRIX=use_world_matrix, KEYFRAME=read_keyframe,
APPLY_MATRIX=use_apply_transform, CONVERSE=global_matrix, APPLY_MATRIX=use_apply_transform, CONVERSE=global_matrix,
) )