Node Wrangler: Improved accuracy on Align Nodes operator #104551

Open
quackarooni wants to merge 18 commits from quackarooni/blender-addons:nw_rework_align_nodes into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
2 changed files with 44 additions and 53 deletions
Showing only changes of commit 1767393035 - Show all commits

View File

@ -23,8 +23,7 @@ bl_info = {
"cameras, lamps & animation",
"warning": "Images must be in file folder, "
"filenames are limited to DOS 8.3 format",
"doc_url": "http://wiki.blender.org/index.php/Extensions:2.6/Py/"
"Scripts/Import-Export/Autodesk_3DS",
"doc_url": "{BLENDER_MANUAL_URL}/addons/import_export/scene_3ds.html",
"category": "Import-Export",
}

View File

@ -7,6 +7,7 @@ from the lib3ds project (http://lib3ds.sourceforge.net/) sourcecode.
"""
import bpy
import time
import math
import struct
import mathutils
@ -332,7 +333,7 @@ class _3ds_rgb_color(object):
class _3ds_face(object):
"""Class representing a face for a 3ds file."""
__slots__ = ("vindex", "flag")
__slots__ = ("vindex", "flag", )
def __init__(self, vindex, flag):
self.vindex = vindex
@ -530,6 +531,10 @@ def make_percent_subchunk(chunk_id, percent):
pcti = _3ds_chunk(PCT)
pcti.add_variable("percent", _3ds_ushort(int(round(percent * 100, 0))))
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
@ -554,9 +559,10 @@ def make_texture_chunk(chunk_id, images):
def make_material_texture_chunk(chunk_id, texslots, pct):
"""Make Material Map texture chunk given a seq. of `MaterialTextureSlot`'s
Paint slots are optionally used as image source if no nodes are
used. No additional filtering for mapping modes is done, all
slots are written "as is"."""
Paint slots are optionally used as image source if no nodes are
used. No additional filtering for mapping modes is done, all
slots are written "as is"."""
# Add texture percentage value
mat_sub = make_percent_subchunk(chunk_id, pct)
has_entry = False
@ -572,19 +578,26 @@ def make_material_texture_chunk(chunk_id, texslots, pct):
socket = link.from_socket.identifier
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
# 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
# CLIP maps to 3DS' decal flag
if texslot.extension == 'CLIP': # no wrap
if texslot.extension == 'CLIP':
mapflags |= 0x10
if socket == 'Alpha':
mapflags |= 0x40 # summed area sampling 0x20
mapflags |= 0x40
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.add_subchunk(mat_sub_mapflags)
@ -635,6 +648,7 @@ def make_material_chunk(material, image):
"""Make a material chunk out of a blender material.
Shading method is required for 3ds max, 0 for wireframe.
0x1 for flat, 0x2 for gouraud, 0x3 for phong and 0x4 for metal."""
material_chunk = _3ds_chunk(MATERIAL)
name = _3ds_chunk(MATNAME)
shading = _3ds_chunk(MATSHADING)
@ -727,7 +741,7 @@ def make_material_chunk(material, image):
diffuse = []
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]
if diffuse:
@ -987,16 +1001,6 @@ def make_uv_chunk(uv_array):
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):
"""Make a chunk out of a Blender mesh."""
@ -1027,14 +1031,12 @@ def make_mesh_chunk(ob, mesh, matrix, materialDict, translation):
if uv_array:
mesh_chunk.add_subchunk(make_uv_chunk(uv_array))
# mesh_chunk.add_subchunk(make_matrix_4x3_chunk(matrix))
# create transformation matrix chunk
matrix_chunk = _3ds_chunk(OBJECT_TRANS_MATRIX)
obj_matrix = matrix.transposed().to_3x3()
if ob.parent is None:
obj_translate = translation[ob.name]
if ob.parent is None or ob.parent.name not in translation:
obj_translate = matrix.to_translation()
else: # Calculate child matrix translation relative to parent
obj_translate = translation[ob.name].cross(-1 * translation[ob.parent.name])
@ -1185,14 +1187,13 @@ def save(operator,
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."""
# Time the export
duration = time.time()
# Blender.Window.WaitCursor(1)
scene = context.scene
layer = context.view_layer
depsgraph = context.evaluated_depsgraph_get()
if global_matrix is None:
global_matrix = mathutils.Matrix()
@ -1200,12 +1201,9 @@ def save(operator,
if bpy.ops.object.mode_set.poll():
bpy.ops.object.mode_set(mode='OBJECT')
scene = context.scene
layer = context.view_layer
depsgraph = context.evaluated_depsgraph_get()
# Initialize the main chunk (primary):
primary = _3ds_chunk(PRIMARY)
# Add version chunk:
version_chunk = _3ds_chunk(VERSION)
version_chunk.add_variable("version", _3ds_uint(3))
@ -1241,16 +1239,16 @@ def save(operator,
mesh_objects = []
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:
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']
camera_objects = [ob for ob in objects if ob.type == 'CAMERA']
for ob in objects:
# get derived objects
# free, derived = create_derived_objects(scene, ob)
derived_dict = bpy_extras.io_utils.create_derived_objects(depsgraph, [ob])
derived = derived_dict.get(ob)
@ -1302,25 +1300,24 @@ def save(operator,
if f.material_index >= ma_ls_len:
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:
for ma_image in materialDict.values():
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:
translation = {} # collect translation for transformation matrix
# name_to_id = {}
for ob, data, matrix in mesh_objects:
translation[ob.name] = ob.location
# name_to_id[ob.name]= len(name_to_id)
"""
#for ob in empty_objects:
# name_to_id[ob.name]= len(name_to_id)
"""
for ob in empty_objects:
translation[ob.name] = ob.location
# name_to_id[ob.name]= len(name_to_id)
# Create object chunks for all meshes:
i = 0
@ -1347,10 +1344,6 @@ def save(operator,
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
# Create chunks for all empties:
@ -1425,9 +1418,9 @@ def save(operator,
'''
# At this point, the chunk hierarchy is completely built.
# Check the size:
primary.get_size()
# Open the file for writing:
file = open(filepath, 'wb')
@ -1442,7 +1435,6 @@ def save(operator,
name_mapping.clear()
# Debugging only: report the exporting time:
# Blender.Window.WaitCursor(0)
print("3ds export time: %.2f" % (time.time() - duration))
# Debugging only: dump the chunk hierarchy: