io_scene_3ds: Added pivot origin option and fixed camera and light ranges #104818

Merged
Sebastian Sille merged 75 commits from :main into main 2023-08-05 00:02:57 +02:00
3 changed files with 55 additions and 31 deletions
Showing only changes of commit 27c7ab156e - Show all commits

View File

@ -57,7 +57,12 @@ class Import3DS(bpy.types.Operator, ImportHelper):
) )
use_scene_unit: BoolProperty( use_scene_unit: BoolProperty(
name="Scene Units", name="Scene Units",
description="Converts to scene unit length settings", description="Convert to scene unit length settings",
default=False,
)
use_center_pivot: BoolProperty(
name="Pivot Origin",
description="Move all geometry to pivot origin",
default=False, default=False,
) )
use_image_search: BoolProperty( use_image_search: BoolProperty(
@ -177,6 +182,9 @@ class MAX3DS_PT_import_transform(bpy.types.Panel):
layrow.prop(operator, "use_scene_unit") layrow.prop(operator, "use_scene_unit")
layrow.label(text="", icon='EMPTY_ARROWS' if operator.use_scene_unit else 'EMPTY_DATA') layrow.label(text="", icon='EMPTY_ARROWS' if operator.use_scene_unit else 'EMPTY_DATA')
layrow = layout.row(align=True) layrow = layout.row(align=True)
layrow.prop(operator, "use_center_pivot")
layrow.label(text="", icon='OVERLAY' if operator.use_center_pivot else 'PIVOT_ACTIVE')
layrow = layout.row(align=True)
layrow.prop(operator, "use_apply_transform") layrow.prop(operator, "use_apply_transform")
layrow.label(text="", icon='MESH_CUBE' if operator.use_apply_transform else 'MOD_SOLIDIFY') layrow.label(text="", icon='MESH_CUBE' if operator.use_apply_transform else 'MOD_SOLIDIFY')
layrow = layout.row(align=True) layrow = layout.row(align=True)

View File

@ -1858,12 +1858,13 @@ def save(operator, context, filepath="", scale_factor=1.0, use_scene_unit=False,
light_inner_range = _3ds_chunk(LIGHT_INNER_RANGE) light_inner_range = _3ds_chunk(LIGHT_INNER_RANGE)
light_outer_range = _3ds_chunk(LIGHT_OUTER_RANGE) light_outer_range = _3ds_chunk(LIGHT_OUTER_RANGE)
light_energy_factor = _3ds_chunk(LIGHT_MULTIPLIER) light_energy_factor = _3ds_chunk(LIGHT_MULTIPLIER)
light_ratio = ob.data.energy if ob.data.type == 'SUN' else ob.data.energy * 0.001
object_chunk.add_variable("light", _3ds_string(sane_name(ob.name))) object_chunk.add_variable("light", _3ds_string(sane_name(ob.name)))
obj_light_chunk.add_variable("location", _3ds_point_3d(light_distance)) obj_light_chunk.add_variable("location", _3ds_point_3d(light_distance))
color_float_chunk.add_variable("color", _3ds_float_color(ob.data.color)) color_float_chunk.add_variable("color", _3ds_float_color(ob.data.color))
light_outer_range.add_variable("distance", _3ds_float(ob.data.cutoff_distance)) light_outer_range.add_variable("distance", _3ds_float(ob.data.cutoff_distance))
light_inner_range.add_variable("radius", _3ds_float(ob.data.shadow_soft_size)) light_inner_range.add_variable("radius", _3ds_float(ob.data.shadow_soft_size * 100))
light_energy_factor.add_variable("energy", _3ds_float(ob.data.energy * 0.001)) light_energy_factor.add_variable("energy", _3ds_float(light_ratio))
obj_light_chunk.add_subchunk(color_float_chunk) obj_light_chunk.add_subchunk(color_float_chunk)
obj_light_chunk.add_subchunk(light_outer_range) obj_light_chunk.add_subchunk(light_outer_range)
obj_light_chunk.add_subchunk(light_inner_range) obj_light_chunk.add_subchunk(light_inner_range)
@ -1943,6 +1944,7 @@ def save(operator, context, filepath="", scale_factor=1.0, use_scene_unit=False,
for ob in camera_objects: for ob in camera_objects:
object_chunk = _3ds_chunk(OBJECT) object_chunk = _3ds_chunk(OBJECT)
camera_chunk = _3ds_chunk(OBJECT_CAMERA) camera_chunk = _3ds_chunk(OBJECT_CAMERA)
crange_chunk = _3ds_chunk(OBJECT_CAM_RANGES)
camera_distance = translation[ob.name] camera_distance = translation[ob.name]
camera_target = calc_target(camera_distance, rotation[ob.name].x, rotation[ob.name].z) camera_target = calc_target(camera_distance, rotation[ob.name].x, rotation[ob.name].z)
object_chunk.add_variable("camera", _3ds_string(sane_name(ob.name))) object_chunk.add_variable("camera", _3ds_string(sane_name(ob.name)))
@ -1950,6 +1952,9 @@ def save(operator, context, filepath="", scale_factor=1.0, use_scene_unit=False,
camera_chunk.add_variable("target", _3ds_point_3d(camera_target)) camera_chunk.add_variable("target", _3ds_point_3d(camera_target))
camera_chunk.add_variable("roll", _3ds_float(round(rotation[ob.name].y, 6))) camera_chunk.add_variable("roll", _3ds_float(round(rotation[ob.name].y, 6)))
camera_chunk.add_variable("lens", _3ds_float(ob.data.lens)) camera_chunk.add_variable("lens", _3ds_float(ob.data.lens))
crange_chunk.add_variable("clipstart", _3ds_float(ob.data.clip_start * 0.1))
crange_chunk.add_variable("clipend", _3ds_float(ob.data.clip_end * 0.1))
camera_chunk.add_subchunk(crange_chunk)
object_chunk.add_subchunk(camera_chunk) object_chunk.add_subchunk(camera_chunk)
# Add hierachy chunks with ID from object_id dictionary # Add hierachy chunks with ID from object_id dictionary

View File

@ -890,24 +890,6 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI
elif CreateWorld and new_chunk.ID in {USE_FOG, USE_LAYER_FOG}: elif CreateWorld and new_chunk.ID in {USE_FOG, USE_LAYER_FOG}:
context.view_layer.use_pass_mist = True context.view_layer.use_pass_mist = True
# If object chunk - can be material and mesh, light and spot or camera
elif new_chunk.ID == OBJECT:
if CreateBlenderObject:
putContextMesh(context, contextMesh_vertls, contextMesh_facels, contextMesh_flag,
contextMeshMaterials, contextMesh_smooth, WORLD_MATRIX)
contextMesh_vertls = []
contextMesh_facels = []
contextMeshMaterials = []
contextMesh_flag = None
contextMesh_smooth = None
contextMeshUV = None
contextMatrix = None
CreateBlenderObject = True if CreateMesh else False
contextObName, read_str_len = read_string(file)
new_chunk.bytes_read += read_str_len
# If material chunk # If material chunk
elif new_chunk.ID == MATERIAL: elif new_chunk.ID == MATERIAL:
contextAlpha = True contextAlpha = True
@ -1058,6 +1040,25 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI
elif new_chunk.ID == MAT_TEX2_MAP: elif new_chunk.ID == MAT_TEX2_MAP:
read_texture(new_chunk, temp_chunk, "Tex", 'TEXTURE') read_texture(new_chunk, temp_chunk, "Tex", 'TEXTURE')
# If object chunk - can be mesh, light and spot or camera
elif new_chunk.ID == OBJECT:
if CreateBlenderObject:
putContextMesh(context, contextMesh_vertls, contextMesh_facels, contextMesh_flag,
contextMeshMaterials, contextMesh_smooth, WORLD_MATRIX)
contextMesh_vertls = []
contextMesh_facels = []
contextMeshMaterials = []
contextMesh_flag = None
contextMesh_smooth = None
contextMeshUV = None
contextMatrix = None
CreateBlenderObject = True if CreateMesh else False
CreateLightObject = CreateCameraObject = False
contextObName, read_str_len = read_string(file)
new_chunk.bytes_read += read_str_len
# If mesh chunk # If mesh chunk
elif new_chunk.ID == OBJECT_MESH: elif new_chunk.ID == OBJECT_MESH:
pass pass
@ -1132,7 +1133,7 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI
elif CreateLightObject and new_chunk.ID == LIGHT_OUTER_RANGE: # Distance elif CreateLightObject and new_chunk.ID == LIGHT_OUTER_RANGE: # Distance
contextLamp.data.cutoff_distance = read_float(new_chunk) contextLamp.data.cutoff_distance = read_float(new_chunk)
elif CreateLightObject and new_chunk.ID == LIGHT_INNER_RANGE: # Radius elif CreateLightObject and new_chunk.ID == LIGHT_INNER_RANGE: # Radius
contextLamp.data.shadow_soft_size = read_float(new_chunk) contextLamp.data.shadow_soft_size = (read_float(new_chunk) * 0.01)
elif CreateLightObject and new_chunk.ID == LIGHT_MULTIPLIER: # Intensity elif CreateLightObject and new_chunk.ID == LIGHT_MULTIPLIER: # Intensity
contextLamp.data.energy = (read_float(new_chunk) * 1000) contextLamp.data.energy = (read_float(new_chunk) * 1000)
elif CreateLightObject and new_chunk.ID == LIGHT_ATTENUATE: # Attenuation elif CreateLightObject and new_chunk.ID == LIGHT_ATTENUATE: # Attenuation
@ -1207,6 +1208,11 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI
contextCamera.rotation_euler.z = direction[1] contextCamera.rotation_euler.z = direction[1]
contextCamera.data.lens = read_float(new_chunk) # Focal length contextCamera.data.lens = read_float(new_chunk) # Focal length
contextMatrix = None # Reset matrix contextMatrix = None # Reset matrix
elif CreateCameraObject and new_chunk.ID == OBJECT_CAM_RANGES: # Range
camrange = read_float(new_chunk)
startrange = camrange if camrange >= 0.01 else 0.1
contextCamera.data.clip_start = startrange * CONSTRAIN
contextCamera.data.clip_end = read_float(new_chunk) * CONSTRAIN
elif CreateCameraObject and new_chunk.ID == OBJECT_HIERARCHY: # Hierarchy elif CreateCameraObject and new_chunk.ID == OBJECT_HIERARCHY: # Hierarchy
child_id = get_hierarchy(new_chunk) child_id = get_hierarchy(new_chunk)
elif CreateCameraObject and new_chunk.ID == OBJECT_PARENT: elif CreateCameraObject and new_chunk.ID == OBJECT_PARENT:
@ -1560,8 +1566,9 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI
# IMPORT # # IMPORT #
########## ##########
def load_3ds(filepath, context, CONSTRAIN=10.0, UNITS=False, IMAGE_SEARCH=True, FILTER=None, def load_3ds(filepath, context, CONSTRAIN=10.0, UNITS=False, IMAGE_SEARCH=True,
WORLD_MATRIX=False, KEYFRAME=True, APPLY_MATRIX=True, CONVERSE=None, CURSOR=False): FILTER=None, WORLD_MATRIX=False, KEYFRAME=True, APPLY_MATRIX=True,
CONVERSE=None, CURSOR=False, PIVOT=False):
print("importing 3DS: %r..." % (filepath), end="") print("importing 3DS: %r..." % (filepath), end="")
@ -1643,9 +1650,13 @@ def load_3ds(filepath, context, CONSTRAIN=10.0, UNITS=False, IMAGE_SEARCH=True,
ob.scale.y = (square / (math.sqrt(pow(aspect,2) + 1.0))) ob.scale.y = (square / (math.sqrt(pow(aspect,2) + 1.0)))
ob.scale.z = 1.0 ob.scale.z = 1.0
ob.select_set(True) ob.select_set(True)
if ob.type == 'MESH':
if PIVOT:
bpy.ops.object.origin_set(type='GEOMETRY_ORIGIN')
if not APPLY_MATRIX: # Reset transform if not APPLY_MATRIX: # Reset transform
bpy.ops.object.rotation_clear() bpy.ops.object.rotation_clear()
bpy.ops.object.location_clear() bpy.ops.object.location_clear()
bpy.ops.object.scale_clear()
""" """
if IMPORT_AS_INSTANCE: if IMPORT_AS_INSTANCE:
@ -1712,11 +1723,11 @@ def load_3ds(filepath, context, CONSTRAIN=10.0, UNITS=False, IMAGE_SEARCH=True,
def load(operator, context, filepath="", constrain_size=0.0, use_scene_unit=False, def load(operator, context, filepath="", constrain_size=0.0, use_scene_unit=False,
use_image_search=True, object_filter=None, use_world_matrix=False, use_image_search=True, object_filter=None, use_world_matrix=False, use_keyframes=True,
use_keyframes=True, use_apply_transform=True, global_matrix=None, use_cursor=False): use_apply_transform=True, global_matrix=None, use_cursor=False, use_center_pivot=False):
load_3ds(filepath, context, CONSTRAIN=constrain_size, UNITS=use_scene_unit, load_3ds(filepath, context, CONSTRAIN=constrain_size, UNITS=use_scene_unit,
IMAGE_SEARCH=use_image_search, FILTER=object_filter, WORLD_MATRIX=use_world_matrix, IMAGE_SEARCH=use_image_search, FILTER=object_filter, WORLD_MATRIX=use_world_matrix, KEYFRAME=use_keyframes,
KEYFRAME=use_keyframes, APPLY_MATRIX=use_apply_transform, CONVERSE=global_matrix, CURSOR=use_cursor,) APPLY_MATRIX=use_apply_transform, CONVERSE=global_matrix, CURSOR=use_cursor, PIVOT=use_center_pivot,)
return {'FINISHED'} return {'FINISHED'}