Node Wrangler: Improved accuracy on Align Nodes operator #104551
@ -23,8 +23,7 @@ bl_info = {
|
|||||||
"cameras, lamps & animation",
|
"cameras, lamps & animation",
|
||||||
"warning": "Images must be in file folder, "
|
"warning": "Images must be in file folder, "
|
||||||
"filenames are limited to DOS 8.3 format",
|
"filenames are limited to DOS 8.3 format",
|
||||||
"doc_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
|
"doc_url": "{BLENDER_MANUAL_URL}/addons/import_export/scene_3ds.html",
|
||||||
"Scripts/Import-Export/Autodesk_3DS",
|
|
||||||
"category": "Import-Export",
|
"category": "Import-Export",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
import time
|
||||||
import math
|
import math
|
||||||
import struct
|
import struct
|
||||||
import mathutils
|
import mathutils
|
||||||
@ -332,7 +333,7 @@ class _3ds_rgb_color(object):
|
|||||||
|
|
||||||
class _3ds_face(object):
|
class _3ds_face(object):
|
||||||
"""Class representing a face for a 3ds file."""
|
"""Class representing a face for a 3ds file."""
|
||||||
__slots__ = ("vindex", "flag")
|
__slots__ = ("vindex", "flag", )
|
||||||
|
|
||||||
def __init__(self, vindex, flag):
|
def __init__(self, vindex, flag):
|
||||||
self.vindex = vindex
|
self.vindex = vindex
|
||||||
@ -530,6 +531,10 @@ def make_percent_subchunk(chunk_id, percent):
|
|||||||
pcti = _3ds_chunk(PCT)
|
pcti = _3ds_chunk(PCT)
|
||||||
pcti.add_variable("percent", _3ds_ushort(int(round(percent * 100, 0))))
|
pcti.add_variable("percent", _3ds_ushort(int(round(percent * 100, 0))))
|
||||||
pct_sub.add_subchunk(pcti)
|
pct_sub.add_subchunk(pcti)
|
||||||
|
# optional:
|
||||||
|
# pctf = _3ds_chunk(PCTF)
|
||||||
|
# pctf.add_variable("pctfloat", _3ds_float(round(percent, 6)))
|
||||||
|
# pct_sub.add_subchunk(pctf)
|
||||||
return pct_sub
|
return pct_sub
|
||||||
|
|
||||||
|
|
||||||
@ -554,9 +559,10 @@ def make_texture_chunk(chunk_id, images):
|
|||||||
|
|
||||||
def make_material_texture_chunk(chunk_id, texslots, pct):
|
def make_material_texture_chunk(chunk_id, texslots, pct):
|
||||||
"""Make Material Map texture chunk given a seq. of `MaterialTextureSlot`'s
|
"""Make Material Map texture chunk given a seq. of `MaterialTextureSlot`'s
|
||||||
Paint slots are optionally used as image source if no nodes are
|
Paint slots are optionally used as image source if no nodes are
|
||||||
used. No additional filtering for mapping modes is done, all
|
used. No additional filtering for mapping modes is done, all
|
||||||
slots are written "as is"."""
|
slots are written "as is"."""
|
||||||
|
|
||||||
# Add texture percentage value
|
# Add texture percentage value
|
||||||
mat_sub = make_percent_subchunk(chunk_id, pct)
|
mat_sub = make_percent_subchunk(chunk_id, pct)
|
||||||
has_entry = False
|
has_entry = False
|
||||||
@ -572,19 +578,26 @@ def make_material_texture_chunk(chunk_id, texslots, pct):
|
|||||||
socket = link.from_socket.identifier
|
socket = link.from_socket.identifier
|
||||||
|
|
||||||
mat_sub_mapflags = _3ds_chunk(MAT_MAP_TILING)
|
mat_sub_mapflags = _3ds_chunk(MAT_MAP_TILING)
|
||||||
|
"""Control bit flags, where 0x1 activates decaling, 0x2 activates mirror,
|
||||||
|
0x8 activates inversion, 0x10 deactivates tiling, 0x20 activates summed area sampling,
|
||||||
|
0x40 activates alpha source, 0x80 activates tinting, 0x100 ignores alpha, 0x200 activates RGB tint.
|
||||||
|
Bits 0x80, 0x100, and 0x200 are only used with TEXMAP, TEX2MAP, and SPECMAP chunks.
|
||||||
|
0x40, when used with a TEXMAP, TEX2MAP, or SPECMAP chunk must be accompanied with a tint bit,
|
||||||
|
either 0x100 or 0x200, tintcolor will be processed if colorchunks are present"""
|
||||||
|
|
||||||
mapflags = 0
|
mapflags = 0
|
||||||
|
|
||||||
# no perfect mapping for mirror modes - 3DS only has uniform mirror w. repeat=2
|
# no perfect mapping for mirror modes - 3DS only has uniform mirror w. repeat=2
|
||||||
if texslot.extension == 'EXTEND': # decal flag
|
if texslot.extension == 'EXTEND':
|
||||||
mapflags |= 0x1
|
mapflags |= 0x1
|
||||||
# CLIP maps to 3DS' decal flag
|
|
||||||
if texslot.extension == 'CLIP': # no wrap
|
if texslot.extension == 'CLIP':
|
||||||
mapflags |= 0x10
|
mapflags |= 0x10
|
||||||
|
|
||||||
if socket == 'Alpha':
|
if socket == 'Alpha':
|
||||||
mapflags |= 0x40 # summed area sampling 0x20
|
mapflags |= 0x40
|
||||||
if texslot.socket_dst.identifier in {'Base Color', 'Specular'}:
|
if texslot.socket_dst.identifier in {'Base Color', 'Specular'}:
|
||||||
mapflags |= 0x80 if image.colorspace_settings.name=='Non-Color' else 0x200 # RGB tint
|
mapflags |= 0x80 if image.colorspace_settings.name=='Non-Color' else 0x200
|
||||||
|
|
||||||
mat_sub_mapflags.add_variable("mapflags", _3ds_ushort(mapflags))
|
mat_sub_mapflags.add_variable("mapflags", _3ds_ushort(mapflags))
|
||||||
mat_sub.add_subchunk(mat_sub_mapflags)
|
mat_sub.add_subchunk(mat_sub_mapflags)
|
||||||
@ -635,6 +648,7 @@ def make_material_chunk(material, image):
|
|||||||
"""Make a material chunk out of a blender material.
|
"""Make a material chunk out of a blender material.
|
||||||
Shading method is required for 3ds max, 0 for wireframe.
|
Shading method is required for 3ds max, 0 for wireframe.
|
||||||
0x1 for flat, 0x2 for gouraud, 0x3 for phong and 0x4 for metal."""
|
0x1 for flat, 0x2 for gouraud, 0x3 for phong and 0x4 for metal."""
|
||||||
|
|
||||||
material_chunk = _3ds_chunk(MATERIAL)
|
material_chunk = _3ds_chunk(MATERIAL)
|
||||||
name = _3ds_chunk(MATNAME)
|
name = _3ds_chunk(MATNAME)
|
||||||
shading = _3ds_chunk(MATSHADING)
|
shading = _3ds_chunk(MATSHADING)
|
||||||
@ -727,7 +741,7 @@ def make_material_chunk(material, image):
|
|||||||
diffuse = []
|
diffuse = []
|
||||||
|
|
||||||
for link in wrap.material.node_tree.links:
|
for link in wrap.material.node_tree.links:
|
||||||
if link.from_node.type == 'TEX_IMAGE' and link.to_node.type == 'MIX_RGB':
|
if link.from_node.type == 'TEX_IMAGE' and link.to_node.type in {'MIX', 'MIX_RGB'}:
|
||||||
diffuse = [link.from_node.image]
|
diffuse = [link.from_node.image]
|
||||||
|
|
||||||
if diffuse:
|
if diffuse:
|
||||||
@ -987,16 +1001,6 @@ def make_uv_chunk(uv_array):
|
|||||||
return uv_chunk
|
return uv_chunk
|
||||||
|
|
||||||
|
|
||||||
'''
|
|
||||||
def make_matrix_4x3_chunk(matrix):
|
|
||||||
matrix_chunk = _3ds_chunk(OBJECT_TRANS_MATRIX)
|
|
||||||
for vec in matrix.col:
|
|
||||||
for f in vec[:3]:
|
|
||||||
matrix_chunk.add_variable("matrix_f", _3ds_float(f))
|
|
||||||
return matrix_chunk
|
|
||||||
'''
|
|
||||||
|
|
||||||
|
|
||||||
def make_mesh_chunk(ob, mesh, matrix, materialDict, translation):
|
def make_mesh_chunk(ob, mesh, matrix, materialDict, translation):
|
||||||
"""Make a chunk out of a Blender mesh."""
|
"""Make a chunk out of a Blender mesh."""
|
||||||
|
|
||||||
@ -1027,14 +1031,12 @@ def make_mesh_chunk(ob, mesh, matrix, materialDict, translation):
|
|||||||
if uv_array:
|
if uv_array:
|
||||||
mesh_chunk.add_subchunk(make_uv_chunk(uv_array))
|
mesh_chunk.add_subchunk(make_uv_chunk(uv_array))
|
||||||
|
|
||||||
# mesh_chunk.add_subchunk(make_matrix_4x3_chunk(matrix))
|
|
||||||
|
|
||||||
# create transformation matrix chunk
|
# create transformation matrix chunk
|
||||||
matrix_chunk = _3ds_chunk(OBJECT_TRANS_MATRIX)
|
matrix_chunk = _3ds_chunk(OBJECT_TRANS_MATRIX)
|
||||||
obj_matrix = matrix.transposed().to_3x3()
|
obj_matrix = matrix.transposed().to_3x3()
|
||||||
|
|
||||||
if ob.parent is None:
|
if ob.parent is None or ob.parent.name not in translation:
|
||||||
obj_translate = translation[ob.name]
|
obj_translate = matrix.to_translation()
|
||||||
|
|
||||||
else: # Calculate child matrix translation relative to parent
|
else: # Calculate child matrix translation relative to parent
|
||||||
obj_translate = translation[ob.name].cross(-1 * translation[ob.parent.name])
|
obj_translate = translation[ob.name].cross(-1 * translation[ob.parent.name])
|
||||||
@ -1185,14 +1187,13 @@ def save(operator,
|
|||||||
global_matrix=None,
|
global_matrix=None,
|
||||||
):
|
):
|
||||||
|
|
||||||
import time
|
|
||||||
# from bpy_extras.io_utils import create_derived_objects, free_derived_objects
|
|
||||||
|
|
||||||
"""Save the Blender scene to a 3ds file."""
|
"""Save the Blender scene to a 3ds file."""
|
||||||
|
|
||||||
# Time the export
|
# Time the export
|
||||||
duration = time.time()
|
duration = time.time()
|
||||||
# Blender.Window.WaitCursor(1)
|
|
||||||
|
scene = context.scene
|
||||||
|
layer = context.view_layer
|
||||||
|
depsgraph = context.evaluated_depsgraph_get()
|
||||||
|
|
||||||
if global_matrix is None:
|
if global_matrix is None:
|
||||||
global_matrix = mathutils.Matrix()
|
global_matrix = mathutils.Matrix()
|
||||||
@ -1200,12 +1201,9 @@ def save(operator,
|
|||||||
if bpy.ops.object.mode_set.poll():
|
if bpy.ops.object.mode_set.poll():
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
|
|
||||||
scene = context.scene
|
|
||||||
layer = context.view_layer
|
|
||||||
depsgraph = context.evaluated_depsgraph_get()
|
|
||||||
|
|
||||||
# Initialize the main chunk (primary):
|
# Initialize the main chunk (primary):
|
||||||
primary = _3ds_chunk(PRIMARY)
|
primary = _3ds_chunk(PRIMARY)
|
||||||
|
|
||||||
# Add version chunk:
|
# Add version chunk:
|
||||||
version_chunk = _3ds_chunk(VERSION)
|
version_chunk = _3ds_chunk(VERSION)
|
||||||
version_chunk.add_variable("version", _3ds_uint(3))
|
version_chunk.add_variable("version", _3ds_uint(3))
|
||||||
@ -1241,16 +1239,16 @@ def save(operator,
|
|||||||
mesh_objects = []
|
mesh_objects = []
|
||||||
|
|
||||||
if use_selection:
|
if use_selection:
|
||||||
objects = [ob for ob in scene.objects if not ob.hide_viewport and ob.select_get(view_layer=layer)]
|
objects = [ob for ob in scene.objects if ob.visible_get(view_layer=layer) and ob.select_get(view_layer=layer)]
|
||||||
else:
|
else:
|
||||||
objects = [ob for ob in scene.objects if not ob.hide_viewport]
|
objects = [ob for ob in scene.objects if ob.visible_get(view_layer=layer)]
|
||||||
|
|
||||||
|
empty_objects = [ob for ob in objects if ob.type == 'EMPTY']
|
||||||
light_objects = [ob for ob in objects if ob.type == 'LIGHT']
|
light_objects = [ob for ob in objects if ob.type == 'LIGHT']
|
||||||
camera_objects = [ob for ob in objects if ob.type == 'CAMERA']
|
camera_objects = [ob for ob in objects if ob.type == 'CAMERA']
|
||||||
|
|
||||||
for ob in objects:
|
for ob in objects:
|
||||||
# get derived objects
|
# get derived objects
|
||||||
# free, derived = create_derived_objects(scene, ob)
|
|
||||||
derived_dict = bpy_extras.io_utils.create_derived_objects(depsgraph, [ob])
|
derived_dict = bpy_extras.io_utils.create_derived_objects(depsgraph, [ob])
|
||||||
derived = derived_dict.get(ob)
|
derived = derived_dict.get(ob)
|
||||||
|
|
||||||
@ -1302,25 +1300,24 @@ def save(operator,
|
|||||||
if f.material_index >= ma_ls_len:
|
if f.material_index >= ma_ls_len:
|
||||||
f.material_index = 0
|
f.material_index = 0
|
||||||
|
|
||||||
# ob_derived_eval.to_mesh_clear()
|
|
||||||
|
|
||||||
# if free:
|
|
||||||
# free_derived_objects(ob)
|
|
||||||
|
|
||||||
# Make material chunks for all materials used in the meshes:
|
# Make material chunks for all materials used in the meshes:
|
||||||
for ma_image in materialDict.values():
|
for ma_image in materialDict.values():
|
||||||
object_info.add_subchunk(make_material_chunk(ma_image[0], ma_image[1]))
|
object_info.add_subchunk(make_material_chunk(ma_image[0], ma_image[1]))
|
||||||
|
|
||||||
|
# Collect translation for transformation matrix
|
||||||
|
translation = {}
|
||||||
|
|
||||||
# Give all objects a unique ID and build a dictionary from object name to object id:
|
# Give all objects a unique ID and build a dictionary from object name to object id:
|
||||||
translation = {} # collect translation for transformation matrix
|
|
||||||
# name_to_id = {}
|
# name_to_id = {}
|
||||||
|
|
||||||
for ob, data, matrix in mesh_objects:
|
for ob, data, matrix in mesh_objects:
|
||||||
translation[ob.name] = ob.location
|
translation[ob.name] = ob.location
|
||||||
# name_to_id[ob.name]= len(name_to_id)
|
# name_to_id[ob.name]= len(name_to_id)
|
||||||
"""
|
|
||||||
#for ob in empty_objects:
|
for ob in empty_objects:
|
||||||
# name_to_id[ob.name]= len(name_to_id)
|
translation[ob.name] = ob.location
|
||||||
"""
|
# name_to_id[ob.name]= len(name_to_id)
|
||||||
|
|
||||||
# Create object chunks for all meshes:
|
# Create object chunks for all meshes:
|
||||||
i = 0
|
i = 0
|
||||||
@ -1347,10 +1344,6 @@ def save(operator,
|
|||||||
kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id))
|
kfdata.add_subchunk(make_kf_obj_node(ob, name_to_id))
|
||||||
'''
|
'''
|
||||||
|
|
||||||
# if not blender_mesh.users:
|
|
||||||
# bpy.data.meshes.remove(blender_mesh)
|
|
||||||
# blender_mesh.vertices = None
|
|
||||||
|
|
||||||
i += i
|
i += i
|
||||||
|
|
||||||
# Create chunks for all empties:
|
# Create chunks for all empties:
|
||||||
@ -1425,9 +1418,9 @@ def save(operator,
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
# At this point, the chunk hierarchy is completely built.
|
# At this point, the chunk hierarchy is completely built.
|
||||||
|
|
||||||
# Check the size:
|
# Check the size:
|
||||||
primary.get_size()
|
primary.get_size()
|
||||||
|
|
||||||
# Open the file for writing:
|
# Open the file for writing:
|
||||||
file = open(filepath, 'wb')
|
file = open(filepath, 'wb')
|
||||||
|
|
||||||
@ -1442,7 +1435,6 @@ def save(operator,
|
|||||||
name_mapping.clear()
|
name_mapping.clear()
|
||||||
|
|
||||||
# Debugging only: report the exporting time:
|
# Debugging only: report the exporting time:
|
||||||
# Blender.Window.WaitCursor(0)
|
|
||||||
print("3ds export time: %.2f" % (time.time() - duration))
|
print("3ds export time: %.2f" % (time.time() - duration))
|
||||||
|
|
||||||
# Debugging only: dump the chunk hierarchy:
|
# Debugging only: dump the chunk hierarchy:
|
||||||
|
Loading…
Reference in New Issue
Block a user