Mesh: Update addons for auto smooth removal #104609
@ -418,7 +418,6 @@ class add_mesh_bolt(Operator, AddObjectHelper):
|
|||||||
(context.active_object.data is not None) and ('Bolt' in context.active_object.data.keys()) and \
|
(context.active_object.data is not None) and ('Bolt' in context.active_object.data.keys()) and \
|
||||||
(self.change == True):
|
(self.change == True):
|
||||||
obj = context.active_object
|
obj = context.active_object
|
||||||
use_auto_smooth = bool(obj.data.use_auto_smooth) # Copy value, do not take a reference
|
|
||||||
use_smooth = bool(obj.data.polygons[0].use_smooth) # Copy value, do not take a reference
|
use_smooth = bool(obj.data.polygons[0].use_smooth) # Copy value, do not take a reference
|
||||||
|
|
||||||
mesh = createMesh.Create_New_Mesh(self, context)
|
mesh = createMesh.Create_New_Mesh(self, context)
|
||||||
@ -430,7 +429,6 @@ class add_mesh_bolt(Operator, AddObjectHelper):
|
|||||||
bm.free()
|
bm.free()
|
||||||
|
|
||||||
# Preserve flat/smooth choice. New mesh is flat by default
|
# Preserve flat/smooth choice. New mesh is flat by default
|
||||||
obj.data.use_auto_smooth = use_auto_smooth
|
|
||||||
if use_smooth:
|
if use_smooth:
|
||||||
bpy.ops.object.shade_smooth()
|
bpy.ops.object.shade_smooth()
|
||||||
else:
|
else:
|
||||||
|
@ -150,9 +150,6 @@ def createMeshObject(context, verts, edges, faces, name):
|
|||||||
# Make a mesh from a list of verts/edges/faces.
|
# Make a mesh from a list of verts/edges/faces.
|
||||||
mesh.from_pydata(verts, edges, faces)
|
mesh.from_pydata(verts, edges, faces)
|
||||||
|
|
||||||
# Set mesh to use auto smoothing:
|
|
||||||
mesh.use_auto_smooth = True
|
|
||||||
|
|
||||||
# Update mesh geometry after adding stuff.
|
# Update mesh geometry after adding stuff.
|
||||||
mesh.update()
|
mesh.update()
|
||||||
|
|
||||||
|
@ -17,11 +17,12 @@ def create_and_link_mesh(name, faces, face_nors, points, global_matrix):
|
|||||||
mesh.from_pydata(points, [], faces)
|
mesh.from_pydata(points, [], faces)
|
||||||
|
|
||||||
if face_nors:
|
if face_nors:
|
||||||
# Note: we store 'temp' normals in loops, since validate() may alter final mesh,
|
# Write imported normals to a temporary attribute so they are interpolated by #mesh.validate().
|
||||||
# we can only set custom lnors *after* calling it.
|
# It's important to validate before calling #mesh.normals_split_custom_set() which expects a
|
||||||
mesh.create_normals_split()
|
# valid mesh.
|
||||||
lnors = tuple(chain(*chain(*zip(face_nors, face_nors, face_nors))))
|
lnors = tuple(chain(*chain(*zip(face_nors, face_nors, face_nors))))
|
||||||
mesh.loops.foreach_set("normal", lnors)
|
mesh.attributes.new("temp_custom_normals", 'FLOAT_VECTOR', 'CORNER')
|
||||||
|
mesh.attributes["temp_custom_normals"].data.foreach_set("vector", lnors)
|
||||||
|
|
||||||
mesh.transform(global_matrix)
|
mesh.transform(global_matrix)
|
||||||
|
|
||||||
@ -30,13 +31,12 @@ def create_and_link_mesh(name, faces, face_nors, points, global_matrix):
|
|||||||
|
|
||||||
if face_nors:
|
if face_nors:
|
||||||
clnors = array.array('f', [0.0] * (len(mesh.loops) * 3))
|
clnors = array.array('f', [0.0] * (len(mesh.loops) * 3))
|
||||||
mesh.loops.foreach_get("normal", clnors)
|
mesh.attributes["temp_custom_normals"].data.foreach_get("vector", clnors)
|
||||||
|
|
||||||
mesh.polygons.foreach_set("use_smooth", [True] * len(mesh.polygons))
|
mesh.polygons.foreach_set("use_smooth", [True] * len(mesh.polygons))
|
||||||
|
|
||||||
mesh.normals_split_custom_set(tuple(zip(*(iter(clnors),) * 3)))
|
mesh.normals_split_custom_set(tuple(zip(*(iter(clnors),) * 3)))
|
||||||
mesh.use_auto_smooth = True
|
mesh.attributes.remove(mesh.attributes["temp_custom_normals"])
|
||||||
mesh.free_normals_split()
|
|
||||||
|
|
||||||
mesh.update()
|
mesh.update()
|
||||||
|
|
||||||
|
@ -1298,12 +1298,9 @@ def make_object_node(ob, translation, rotation, scale, name_id):
|
|||||||
obj_node_header_chunk.add_variable("name", _3ds_string(sane_name(name)))
|
obj_node_header_chunk.add_variable("name", _3ds_string(sane_name(name)))
|
||||||
obj_node_header_chunk.add_variable("flags1", _3ds_ushort(0x0040))
|
obj_node_header_chunk.add_variable("flags1", _3ds_ushort(0x0040))
|
||||||
|
|
||||||
"""Flags2 defines 0x01 for display path, 0x02 use autosmooth, 0x04 object frozen,
|
"""Flags2 defines 0x01 for display path, 0x04 object frozen,
|
||||||
0x10 for motion blur, 0x20 for material morph and bit 0x40 for mesh morph."""
|
0x10 for motion blur, 0x20 for material morph and bit 0x40 for mesh morph."""
|
||||||
if ob.type == 'MESH' and ob.data.use_auto_smooth:
|
obj_node_header_chunk.add_variable("flags2", _3ds_ushort(0))
|
||||||
obj_node_header_chunk.add_variable("flags2", _3ds_ushort(0x02))
|
|
||||||
else:
|
|
||||||
obj_node_header_chunk.add_variable("flags2", _3ds_ushort(0))
|
|
||||||
obj_node_header_chunk.add_variable("parent", _3ds_ushort(ROOT_OBJECT))
|
obj_node_header_chunk.add_variable("parent", _3ds_ushort(ROOT_OBJECT))
|
||||||
|
|
||||||
'''
|
'''
|
||||||
@ -1343,12 +1340,6 @@ def make_object_node(ob, translation, rotation, scale, name_id):
|
|||||||
obj_boundbox.add_variable("max", _3ds_point_3d(ob.bound_box[6]))
|
obj_boundbox.add_variable("max", _3ds_point_3d(ob.bound_box[6]))
|
||||||
obj_node.add_subchunk(obj_boundbox)
|
obj_node.add_subchunk(obj_boundbox)
|
||||||
|
|
||||||
# Add smooth angle if autosmooth is used
|
|
||||||
if ob.type == 'MESH' and ob.data.use_auto_smooth:
|
|
||||||
obj_morph_smooth = _3ds_chunk(OBJECT_MORPH_SMOOTH)
|
|
||||||
obj_morph_smooth.add_variable("angle", _3ds_float(round(ob.data.auto_smooth_angle, 6)))
|
|
||||||
obj_node.add_subchunk(obj_morph_smooth)
|
|
||||||
|
|
||||||
# Add track chunks for position, rotation, size
|
# Add track chunks for position, rotation, size
|
||||||
ob_scale = scale[name] # and collect masterscale
|
ob_scale = scale[name] # and collect masterscale
|
||||||
if parent is None or (parent.name not in name_id):
|
if parent is None or (parent.name not in name_id):
|
||||||
|
@ -1331,8 +1331,7 @@ def process_next_chunk(context, file, previous_chunk, imported_objects, CONSTRAI
|
|||||||
elif new_chunk.ID == MORPH_SMOOTH and tracking == 'OBJECT': # Smooth angle
|
elif new_chunk.ID == MORPH_SMOOTH and tracking == 'OBJECT': # Smooth angle
|
||||||
smooth_angle = read_float(new_chunk)
|
smooth_angle = read_float(new_chunk)
|
||||||
if child.data is not None: # Check if child is a dummy
|
if child.data is not None: # Check if child is a dummy
|
||||||
child.data.use_auto_smooth = True
|
child.data.set_sharp_from_angle(smooth_angle)
|
||||||
child.data.auto_smooth_angle = smooth_angle
|
|
||||||
|
|
||||||
elif KEYFRAME and new_chunk.ID == COL_TRACK_TAG and tracking == 'AMBIENT': # Ambient
|
elif KEYFRAME and new_chunk.ID == COL_TRACK_TAG and tracking == 'AMBIENT': # Ambient
|
||||||
keyframe_data = {}
|
keyframe_data = {}
|
||||||
|
@ -1158,7 +1158,6 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
|
|||||||
# NOTE: this is not supported by importer currently.
|
# NOTE: this is not supported by importer currently.
|
||||||
# XXX Official docs says normals should use IndexToDirect,
|
# XXX Official docs says normals should use IndexToDirect,
|
||||||
# but this does not seem well supported by apps currently...
|
# but this does not seem well supported by apps currently...
|
||||||
me.calc_normals_split()
|
|
||||||
|
|
||||||
ln_bl_dtype = np.single
|
ln_bl_dtype = np.single
|
||||||
ln_fbx_dtype = np.float64
|
ln_fbx_dtype = np.float64
|
||||||
@ -1258,8 +1257,6 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
|
|||||||
# del t_lnw
|
# del t_lnw
|
||||||
me.free_tangents()
|
me.free_tangents()
|
||||||
|
|
||||||
me.free_normals_split()
|
|
||||||
|
|
||||||
# Write VertexColor Layers.
|
# Write VertexColor Layers.
|
||||||
colors_type = scene_data.settings.colors_type
|
colors_type = scene_data.settings.colors_type
|
||||||
vcolnumber = 0 if colors_type == 'NONE' else len(me.color_attributes)
|
vcolnumber = 0 if colors_type == 'NONE' else len(me.color_attributes)
|
||||||
|
@ -1653,8 +1653,6 @@ def blen_read_geom_layer_smooth(fbx_obj, mesh):
|
|||||||
1, fbx_item_size, layer_id,
|
1, fbx_item_size, layer_id,
|
||||||
xform=np.logical_not, # in FBX, 0 (False) is sharp, but in Blender True is sharp.
|
xform=np.logical_not, # in FBX, 0 (False) is sharp, but in Blender True is sharp.
|
||||||
)
|
)
|
||||||
# We only set sharp edges here, not face smoothing itself...
|
|
||||||
mesh.use_auto_smooth = True
|
|
||||||
return False
|
return False
|
||||||
elif fbx_layer_mapping == b'ByPolygon':
|
elif fbx_layer_mapping == b'ByPolygon':
|
||||||
blen_data = MESH_ATTRIBUTE_SHARP_FACE.ensure(mesh.attributes).data
|
blen_data = MESH_ATTRIBUTE_SHARP_FACE.ensure(mesh.attributes).data
|
||||||
@ -1737,23 +1735,23 @@ def blen_read_geom_layer_normal(fbx_obj, mesh, xform=None):
|
|||||||
bl_norm_dtype = np.single
|
bl_norm_dtype = np.single
|
||||||
item_size = 3
|
item_size = 3
|
||||||
# try loops, then polygons, then vertices.
|
# try loops, then polygons, then vertices.
|
||||||
tries = ((mesh.loops, "Loops", False, blen_read_geom_array_mapped_polyloop),
|
tries = ((mesh.attributes["temp_custom_normals"].data, "Loops", False, blen_read_geom_array_mapped_polyloop),
|
||||||
(mesh.polygons, "Polygons", True, blen_read_geom_array_mapped_polygon),
|
(mesh.polygons, "Polygons", True, blen_read_geom_array_mapped_polygon),
|
||||||
(mesh.vertices, "Vertices", True, blen_read_geom_array_mapped_vert))
|
(mesh.vertices, "Vertices", True, blen_read_geom_array_mapped_vert))
|
||||||
for blen_data, blen_data_type, is_fake, func in tries:
|
for blen_data, blen_data_type, is_fake, func in tries:
|
||||||
bdata = np.zeros((len(blen_data), item_size), dtype=bl_norm_dtype) if is_fake else blen_data
|
bdata = np.zeros((len(blen_data), item_size), dtype=bl_norm_dtype) if is_fake else blen_data
|
||||||
if func(mesh, bdata, "normal", bl_norm_dtype,
|
if func(mesh, bdata, "vector", bl_norm_dtype,
|
||||||
fbx_layer_data, fbx_layer_index, fbx_layer_mapping, fbx_layer_ref, 3, item_size, layer_id, xform, True):
|
fbx_layer_data, fbx_layer_index, fbx_layer_mapping, fbx_layer_ref, 3, item_size, layer_id, xform, True):
|
||||||
if blen_data_type == "Polygons":
|
if blen_data_type == "Polygons":
|
||||||
# To expand to per-loop normals, repeat each per-polygon normal by the number of loops of each polygon.
|
# To expand to per-loop normals, repeat each per-polygon normal by the number of loops of each polygon.
|
||||||
poly_loop_totals = np.empty(len(mesh.polygons), dtype=np.uintc)
|
poly_loop_totals = np.empty(len(mesh.polygons), dtype=np.uintc)
|
||||||
mesh.polygons.foreach_get("loop_total", poly_loop_totals)
|
mesh.polygons.foreach_get("loop_total", poly_loop_totals)
|
||||||
loop_normals = np.repeat(bdata, poly_loop_totals, axis=0)
|
loop_normals = np.repeat(bdata, poly_loop_totals, axis=0)
|
||||||
mesh.loops.foreach_set("normal", loop_normals.ravel())
|
mesh.attributes["temp_custom_normals"].data.foreach_set("normal", loop_normals.ravel())
|
||||||
elif blen_data_type == "Vertices":
|
elif blen_data_type == "Vertices":
|
||||||
# We have to copy vnors to lnors! Far from elegant, but simple.
|
# We have to copy vnors to lnors! Far from elegant, but simple.
|
||||||
loop_vertex_indices = MESH_ATTRIBUTE_CORNER_VERT.to_ndarray(mesh.attributes)
|
loop_vertex_indices = MESH_ATTRIBUTE_CORNER_VERT.to_ndarray(mesh.attributes)
|
||||||
mesh.loops.foreach_set("normal", bdata[loop_vertex_indices].ravel())
|
mesh.attributes["temp_custom_normals"].data.foreach_set("normal", bdata[loop_vertex_indices].ravel())
|
||||||
return True
|
return True
|
||||||
|
|
||||||
blen_read_geom_array_error_mapping("normal", fbx_layer_mapping)
|
blen_read_geom_array_error_mapping("normal", fbx_layer_mapping)
|
||||||
@ -1877,7 +1875,7 @@ def blen_read_geom(fbx_tmpl, fbx_obj, settings):
|
|||||||
if settings.use_custom_normals:
|
if settings.use_custom_normals:
|
||||||
# Note: we store 'temp' normals in loops, since validate() may alter final mesh,
|
# Note: we store 'temp' normals in loops, since validate() may alter final mesh,
|
||||||
# we can only set custom lnors *after* calling it.
|
# we can only set custom lnors *after* calling it.
|
||||||
mesh.create_normals_split()
|
mesh.attributes.new("temp_custom_normals", 'FLOAT_VECTOR', 'CORNER')
|
||||||
if geom_mat_no is None:
|
if geom_mat_no is None:
|
||||||
ok_normals = blen_read_geom_layer_normal(fbx_obj, mesh)
|
ok_normals = blen_read_geom_layer_normal(fbx_obj, mesh)
|
||||||
else:
|
else:
|
||||||
@ -1889,7 +1887,7 @@ def blen_read_geom(fbx_tmpl, fbx_obj, settings):
|
|||||||
if ok_normals:
|
if ok_normals:
|
||||||
bl_nors_dtype = np.single
|
bl_nors_dtype = np.single
|
||||||
clnors = np.empty(len(mesh.loops) * 3, dtype=bl_nors_dtype)
|
clnors = np.empty(len(mesh.loops) * 3, dtype=bl_nors_dtype)
|
||||||
mesh.loops.foreach_get("normal", clnors)
|
mesh.attributes["temp_custom_normals"].data.foreach_get("vector", clnors)
|
||||||
|
|
||||||
if not ok_smooth:
|
if not ok_smooth:
|
||||||
sharp_face = MESH_ATTRIBUTE_SHARP_FACE.get(attributes)
|
sharp_face = MESH_ATTRIBUTE_SHARP_FACE.get(attributes)
|
||||||
@ -1900,10 +1898,8 @@ def blen_read_geom(fbx_tmpl, fbx_obj, settings):
|
|||||||
# Iterating clnors into a nested tuple first is faster than passing clnors.reshape(-1, 3) directly into
|
# Iterating clnors into a nested tuple first is faster than passing clnors.reshape(-1, 3) directly into
|
||||||
# normals_split_custom_set. We use clnors.data since it is a memoryview, which is faster to iterate than clnors.
|
# normals_split_custom_set. We use clnors.data since it is a memoryview, which is faster to iterate than clnors.
|
||||||
mesh.normals_split_custom_set(tuple(zip(*(iter(clnors.data),) * 3)))
|
mesh.normals_split_custom_set(tuple(zip(*(iter(clnors.data),) * 3)))
|
||||||
mesh.use_auto_smooth = True
|
|
||||||
|
|
||||||
if settings.use_custom_normals:
|
if settings.use_custom_normals:
|
||||||
mesh.free_normals_split()
|
mesh.attributes.remove(mesh.attributes["temp_custom_normals"])
|
||||||
|
|
||||||
if not ok_smooth:
|
if not ok_smooth:
|
||||||
sharp_face = MESH_ATTRIBUTE_SHARP_FACE.get(attributes)
|
sharp_face = MESH_ATTRIBUTE_SHARP_FACE.get(attributes)
|
||||||
|
@ -64,8 +64,6 @@ class PrimitiveCreator:
|
|||||||
self.blender_object = self.export_settings['vtree'].nodes[self.uuid_for_skined_data].blender_object
|
self.blender_object = self.export_settings['vtree'].nodes[self.uuid_for_skined_data].blender_object
|
||||||
|
|
||||||
self.use_normals = self.export_settings['gltf_normals']
|
self.use_normals = self.export_settings['gltf_normals']
|
||||||
if self.use_normals:
|
|
||||||
self.blender_mesh.calc_normals_split()
|
|
||||||
|
|
||||||
self.use_tangents = False
|
self.use_tangents = False
|
||||||
if self.use_normals and self.export_settings['gltf_tangents']:
|
if self.use_normals and self.export_settings['gltf_tangents']:
|
||||||
@ -776,7 +774,6 @@ class PrimitiveCreator:
|
|||||||
self.normals = np.array(self.normals, dtype=np.float32)
|
self.normals = np.array(self.normals, dtype=np.float32)
|
||||||
else:
|
else:
|
||||||
self.normals = np.empty(len(self.blender_mesh.loops) * 3, dtype=np.float32)
|
self.normals = np.empty(len(self.blender_mesh.loops) * 3, dtype=np.float32)
|
||||||
self.blender_mesh.calc_normals_split()
|
|
||||||
self.blender_mesh.loops.foreach_get('normal', self.normals)
|
self.blender_mesh.loops.foreach_get('normal', self.normals)
|
||||||
|
|
||||||
self.normals = self.normals.reshape(len(self.blender_mesh.loops), 3)
|
self.normals = self.normals.reshape(len(self.blender_mesh.loops), 3)
|
||||||
|
@ -61,10 +61,9 @@ def do_primitives(gltf, mesh_idx, skin_idx, mesh, ob):
|
|||||||
|
|
||||||
# Use a class here, to be able to pass data by reference to hook (to be able to change them inside hook)
|
# Use a class here, to be able to pass data by reference to hook (to be able to change them inside hook)
|
||||||
class IMPORT_mesh_options:
|
class IMPORT_mesh_options:
|
||||||
def __init__(self, skinning: bool = True, skin_into_bind_pose: bool = True, use_auto_smooth: bool = True):
|
def __init__(self, skinning: bool = True, skin_into_bind_pose: bool = True):
|
||||||
self.skinning = skinning
|
self.skinning = skinning
|
||||||
self.skin_into_bind_pose = skin_into_bind_pose
|
self.skin_into_bind_pose = skin_into_bind_pose
|
||||||
self.use_auto_smooth = use_auto_smooth
|
|
||||||
|
|
||||||
mesh_options = IMPORT_mesh_options()
|
mesh_options = IMPORT_mesh_options()
|
||||||
import_user_extensions('gather_import_mesh_options', gltf, mesh_options, pymesh, skin_idx)
|
import_user_extensions('gather_import_mesh_options', gltf, mesh_options, pymesh, skin_idx)
|
||||||
@ -479,9 +478,7 @@ def do_primitives(gltf, mesh_idx, skin_idx, mesh, ob):
|
|||||||
mesh.update(calc_edges_loose=has_loose_edges)
|
mesh.update(calc_edges_loose=has_loose_edges)
|
||||||
|
|
||||||
if has_normals:
|
if has_normals:
|
||||||
mesh.create_normals_split()
|
|
||||||
mesh.normals_split_custom_set_from_vertices(vert_normals)
|
mesh.normals_split_custom_set_from_vertices(vert_normals)
|
||||||
mesh.use_auto_smooth = mesh_options.use_auto_smooth
|
|
||||||
|
|
||||||
|
|
||||||
def points_edges_tris(mode, indices):
|
def points_edges_tris(mode, indices):
|
||||||
|
@ -819,10 +819,6 @@ def export(file,
|
|||||||
|
|
||||||
# --- Write IndexedFaceSet Attributes (same as IndexedTriangleSet)
|
# --- Write IndexedFaceSet Attributes (same as IndexedTriangleSet)
|
||||||
fw('solid="%s"\n' % bool_as_str(material and material.use_backface_culling))
|
fw('solid="%s"\n' % bool_as_str(material and material.use_backface_culling))
|
||||||
if is_smooth:
|
|
||||||
# use Auto-Smooth angle, if enabled. Otherwise make
|
|
||||||
# the mesh perfectly smooth by creaseAngle > pi.
|
|
||||||
fw(ident_step + 'creaseAngle="%.4f"\n' % (mesh.auto_smooth_angle if mesh.use_auto_smooth else 4.0))
|
|
||||||
|
|
||||||
if use_normals:
|
if use_normals:
|
||||||
# currently not optional, could be made so:
|
# currently not optional, could be made so:
|
||||||
|
@ -3013,8 +3013,7 @@ def importShape_ProcessObject(
|
|||||||
# solid=false, we don't support it yet.
|
# solid=false, we don't support it yet.
|
||||||
creaseAngle = geom.getFieldAsFloat('creaseAngle', None, ancestry)
|
creaseAngle = geom.getFieldAsFloat('creaseAngle', None, ancestry)
|
||||||
if creaseAngle is not None:
|
if creaseAngle is not None:
|
||||||
bpydata.auto_smooth_angle = creaseAngle
|
bpydata.set_sharp_from_angle(creaseAngle)
|
||||||
bpydata.use_auto_smooth = True
|
|
||||||
else:
|
else:
|
||||||
bpydata.polygons.foreach_set("use_smooth", [False] * len(bpydata.polygons))
|
bpydata.polygons.foreach_set("use_smooth", [False] * len(bpydata.polygons))
|
||||||
|
|
||||||
|
@ -677,8 +677,7 @@ def mu_set_auto_smooth(self, angle, affect, set_smooth_shading):
|
|||||||
|
|
||||||
#bpy.ops.object.shade_smooth()
|
#bpy.ops.object.shade_smooth()
|
||||||
|
|
||||||
object.data.use_auto_smooth = 1
|
object.data.set_sharp_from_angle(angle) # 35 degrees as radians
|
||||||
object.data.auto_smooth_angle = angle # 35 degrees as radians
|
|
||||||
|
|
||||||
objects_affected += 1
|
objects_affected += 1
|
||||||
|
|
||||||
|
@ -171,13 +171,6 @@ class VIEW3D_MT_materialutilities_specials(bpy.types.Menu):
|
|||||||
text = "Join by material",
|
text = "Join by material",
|
||||||
icon = "OBJECT_DATAMODE")
|
icon = "OBJECT_DATAMODE")
|
||||||
|
|
||||||
layout.separator()
|
|
||||||
|
|
||||||
op = layout.operator(MATERIAL_OT_materialutilities_auto_smooth_angle.bl_idname,
|
|
||||||
text = "Set Auto Smooth",
|
|
||||||
icon = "SHADING_SOLID")
|
|
||||||
op.affect = mu_prefs.set_smooth_affect
|
|
||||||
op.angle = mu_prefs.auto_smooth_angle
|
|
||||||
|
|
||||||
class VIEW3D_MT_materialutilities_main(bpy.types.Menu):
|
class VIEW3D_MT_materialutilities_main(bpy.types.Menu):
|
||||||
"""Main menu for Material Utilities"""
|
"""Main menu for Material Utilities"""
|
||||||
|
@ -68,20 +68,6 @@ class VIEW3D_MT_materialutilities_preferences(AddonPreferences):
|
|||||||
default = 0
|
default = 0
|
||||||
)
|
)
|
||||||
|
|
||||||
set_smooth_affect: EnumProperty(
|
|
||||||
name = "Set Auto Smooth Affect",
|
|
||||||
description = "Which objects to affect",
|
|
||||||
items = mu_affect_enums,
|
|
||||||
default = 'SELECTED'
|
|
||||||
)
|
|
||||||
auto_smooth_angle: FloatProperty(
|
|
||||||
name = "Auto Smooth Angle",
|
|
||||||
description = "Maximum angle between face normals that will be considered as smooth",
|
|
||||||
subtype = 'ANGLE',
|
|
||||||
min = 0,
|
|
||||||
max = radians(180),
|
|
||||||
default = radians(35)
|
|
||||||
)
|
|
||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
@ -105,11 +91,6 @@ class VIEW3D_MT_materialutilities_preferences(AddonPreferences):
|
|||||||
c.row().prop(self, "link_to", expand = False)
|
c.row().prop(self, "link_to", expand = False)
|
||||||
c.row().prop(self, "link_to_affect", expand = False)
|
c.row().prop(self, "link_to_affect", expand = False)
|
||||||
|
|
||||||
d = box.box()
|
|
||||||
d.label(text = "Set Auto Smooth")
|
|
||||||
d.row().prop(self, "auto_smooth_angle", expand = False)
|
|
||||||
d.row().prop(self, "set_smooth_affect", expand = False)
|
|
||||||
|
|
||||||
box = layout.box()
|
box = layout.box()
|
||||||
box.label(text = "Miscellaneous")
|
box.label(text = "Miscellaneous")
|
||||||
|
|
||||||
|
@ -802,7 +802,6 @@ def tessellate_patch(props):
|
|||||||
n2 = n2[masked_faces][:,None,:]
|
n2 = n2[masked_faces][:,None,:]
|
||||||
else:
|
else:
|
||||||
if normals_mode == 'CUSTOM':
|
if normals_mode == 'CUSTOM':
|
||||||
me0.calc_normals_split()
|
|
||||||
normals_split = [0]*len(me0.loops)*3
|
normals_split = [0]*len(me0.loops)*3
|
||||||
vertex_indexes = [0]*len(me0.loops)
|
vertex_indexes = [0]*len(me0.loops)
|
||||||
me0.loops.foreach_get('normal', normals_split)
|
me0.loops.foreach_get('normal', normals_split)
|
||||||
|
@ -338,8 +338,7 @@ def CreateBevel(context, CurrentObject):
|
|||||||
|
|
||||||
bpy.ops.object.shade_smooth()
|
bpy.ops.object.shade_smooth()
|
||||||
|
|
||||||
context.object.data.use_auto_smooth = True
|
context.object.data.set_sharp_from_angle(1.0471975)
|
||||||
context.object.data.auto_smooth_angle = 1.0471975
|
|
||||||
|
|
||||||
# Restore the active object
|
# Restore the active object
|
||||||
context.view_layer.objects.active = SavActive
|
context.view_layer.objects.active = SavActive
|
||||||
|
@ -108,12 +108,6 @@ class PovDataButtonsPanel(properties_data_mesh.MeshButtonsPanel):
|
|||||||
# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
|
# We cannot inherit from RNA classes (like e.g. properties_data_mesh.DATA_PT_vertex_groups).
|
||||||
# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
|
# Complex py/bpy/rna interactions (with metaclass and all) simply do not allow it to work.
|
||||||
# So we simply have to explicitly copy here the interesting bits. ;)
|
# So we simply have to explicitly copy here the interesting bits. ;)
|
||||||
class DATA_PT_POV_normals(PovDataButtonsPanel, Panel):
|
|
||||||
bl_label = properties_data_mesh.DATA_PT_normals.bl_label
|
|
||||||
|
|
||||||
draw = properties_data_mesh.DATA_PT_normals.draw
|
|
||||||
|
|
||||||
|
|
||||||
class DATA_PT_POV_texture_space(PovDataButtonsPanel, Panel):
|
class DATA_PT_POV_texture_space(PovDataButtonsPanel, Panel):
|
||||||
bl_label = properties_data_mesh.DATA_PT_texture_space.bl_label
|
bl_label = properties_data_mesh.DATA_PT_texture_space.bl_label
|
||||||
bl_options = properties_data_mesh.DATA_PT_texture_space.bl_options
|
bl_options = properties_data_mesh.DATA_PT_texture_space.bl_options
|
||||||
@ -1066,7 +1060,6 @@ class VIEW_WT_POV_blobcube_add(WorkSpaceTool):
|
|||||||
classes = (
|
classes = (
|
||||||
# ObjectButtonsPanel,
|
# ObjectButtonsPanel,
|
||||||
# PovDataButtonsPanel,
|
# PovDataButtonsPanel,
|
||||||
DATA_PT_POV_normals,
|
|
||||||
DATA_PT_POV_texture_space,
|
DATA_PT_POV_texture_space,
|
||||||
DATA_PT_POV_vertex_groups,
|
DATA_PT_POV_vertex_groups,
|
||||||
DATA_PT_POV_shape_keys,
|
DATA_PT_POV_shape_keys,
|
||||||
|
@ -180,7 +180,6 @@ def pov_cylinder_define(context, op, ob, radius, loc, loc_cap):
|
|||||||
ob.name = ob.data.name = "PovCylinder"
|
ob.name = ob.data.name = "PovCylinder"
|
||||||
ob.pov.cylinder_radius = radius
|
ob.pov.cylinder_radius = radius
|
||||||
ob.pov.cylinder_location_cap = vec
|
ob.pov.cylinder_location_cap = vec
|
||||||
ob.data.use_auto_smooth = True
|
|
||||||
ob.pov.object_as = "CYLINDER"
|
ob.pov.object_as = "CYLINDER"
|
||||||
ob.update_tag() # as prop set via python not updated in depsgraph
|
ob.update_tag() # as prop set via python not updated in depsgraph
|
||||||
|
|
||||||
@ -326,7 +325,6 @@ def pov_sphere_define(context, op, ob, loc):
|
|||||||
bpy.ops.object.mode_set(mode="EDIT")
|
bpy.ops.object.mode_set(mode="EDIT")
|
||||||
bpy.ops.mesh.hide(unselected=False)
|
bpy.ops.mesh.hide(unselected=False)
|
||||||
bpy.ops.object.mode_set(mode="OBJECT")
|
bpy.ops.object.mode_set(mode="OBJECT")
|
||||||
ob.data.use_auto_smooth = True
|
|
||||||
bpy.ops.object.shade_smooth()
|
bpy.ops.object.shade_smooth()
|
||||||
ob.pov.object_as = "SPHERE"
|
ob.pov.object_as = "SPHERE"
|
||||||
ob.update_tag() # as prop set via python not updated in depsgraph
|
ob.update_tag() # as prop set via python not updated in depsgraph
|
||||||
@ -471,7 +469,6 @@ def pov_cone_define(context, op, ob):
|
|||||||
ob.pov.cone_height = height
|
ob.pov.cone_height = height
|
||||||
ob.pov.cone_base_z = zb
|
ob.pov.cone_base_z = zb
|
||||||
ob.pov.cone_cap_z = zc
|
ob.pov.cone_cap_z = zc
|
||||||
ob.data.use_auto_smooth = True
|
|
||||||
bpy.ops.object.shade_smooth()
|
bpy.ops.object.shade_smooth()
|
||||||
ob.pov.object_as = "CONE"
|
ob.pov.object_as = "CONE"
|
||||||
ob.update_tag() # as prop set via python not updated in depsgraph
|
ob.update_tag() # as prop set via python not updated in depsgraph
|
||||||
@ -659,9 +656,7 @@ def pov_torus_define(context, op, ob):
|
|||||||
bpy.ops.object.mode_set(mode="EDIT")
|
bpy.ops.object.mode_set(mode="EDIT")
|
||||||
bpy.ops.mesh.hide(unselected=False)
|
bpy.ops.mesh.hide(unselected=False)
|
||||||
bpy.ops.object.mode_set(mode="OBJECT")
|
bpy.ops.object.mode_set(mode="OBJECT")
|
||||||
ob.data.use_auto_smooth = True
|
ob.data.set_sharp_from_angle(0.6)
|
||||||
ob.data.auto_smooth_angle = 0.6
|
|
||||||
bpy.ops.object.shade_smooth()
|
|
||||||
ob.pov.object_as = "TORUS"
|
ob.pov.object_as = "TORUS"
|
||||||
ob.update_tag() # as prop set via python not updated in depsgraph
|
ob.update_tag() # as prop set via python not updated in depsgraph
|
||||||
|
|
||||||
|
@ -171,8 +171,7 @@ def pov_superellipsoid_define(context, op, ob):
|
|||||||
bpy.ops.object.mode_set(mode="EDIT")
|
bpy.ops.object.mode_set(mode="EDIT")
|
||||||
bpy.ops.mesh.hide(unselected=False)
|
bpy.ops.mesh.hide(unselected=False)
|
||||||
bpy.ops.object.mode_set(mode="OBJECT")
|
bpy.ops.object.mode_set(mode="OBJECT")
|
||||||
ob.data.auto_smooth_angle = 1.3
|
ob.data.set_sharp_from_angle(1.3)
|
||||||
bpy.ops.object.shade_smooth()
|
|
||||||
ob.pov.object_as = "SUPERELLIPSOID"
|
ob.pov.object_as = "SUPERELLIPSOID"
|
||||||
ob.update_tag() # as prop set via python not updated in depsgraph
|
ob.update_tag() # as prop set via python not updated in depsgraph
|
||||||
|
|
||||||
@ -1051,8 +1050,7 @@ def pov_parametric_define(context, op, ob):
|
|||||||
bpy.ops.object.mode_set(mode="EDIT")
|
bpy.ops.object.mode_set(mode="EDIT")
|
||||||
bpy.ops.mesh.hide(unselected=False)
|
bpy.ops.mesh.hide(unselected=False)
|
||||||
bpy.ops.object.mode_set(mode="OBJECT")
|
bpy.ops.object.mode_set(mode="OBJECT")
|
||||||
ob.data.auto_smooth_angle = 0.6
|
ob.data.set_sharp_from_angle(0.6)
|
||||||
bpy.ops.object.shade_smooth()
|
|
||||||
ob.pov.object_as = "PARAMETRIC"
|
ob.pov.object_as = "PARAMETRIC"
|
||||||
ob.update_tag() # as prop set via python not updated in depsgraph
|
ob.update_tag() # as prop set via python not updated in depsgraph
|
||||||
return{'FINISHED'}
|
return{'FINISHED'}
|
||||||
@ -1180,8 +1178,6 @@ class POV_OT_polygon_to_circle_add(Operator):
|
|||||||
bpy.ops.object.mode_set(mode="EDIT")
|
bpy.ops.object.mode_set(mode="EDIT")
|
||||||
bpy.ops.mesh.hide(unselected=False)
|
bpy.ops.mesh.hide(unselected=False)
|
||||||
bpy.ops.object.mode_set(mode="OBJECT")
|
bpy.ops.object.mode_set(mode="OBJECT")
|
||||||
#ob.data.auto_smooth_angle = 0.1
|
|
||||||
#bpy.ops.object.shade_smooth()
|
|
||||||
ob.pov.object_as = "POLYCIRCLE"
|
ob.pov.object_as = "POLYCIRCLE"
|
||||||
ob.update_tag() # as prop set via python not updated in depsgraph
|
ob.update_tag() # as prop set via python not updated in depsgraph
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
@ -180,21 +180,6 @@ class VIEW3D_OT_selecteditVertsEdgesFaces(Operator):
|
|||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
# ********** Normals / Auto Smooth Menu **********
|
|
||||||
# Thanks to marvin.k.breuer for the Autosmooth part of the menu
|
|
||||||
|
|
||||||
def menu_func(self, context):
|
|
||||||
layout = self.layout
|
|
||||||
obj = context.object
|
|
||||||
obj_data = context.active_object.data
|
|
||||||
layout.separator()
|
|
||||||
layout.prop(obj_data, "use_auto_smooth", text="Normals: Auto Smooth")
|
|
||||||
|
|
||||||
# Auto Smooth Angle - two tab spaces to align it with the rest of the menu
|
|
||||||
layout.prop(obj_data, "auto_smooth_angle",
|
|
||||||
text=" Auto Smooth Angle")
|
|
||||||
|
|
||||||
|
|
||||||
# List The Classes #
|
# List The Classes #
|
||||||
|
|
||||||
classes = (
|
classes = (
|
||||||
@ -215,7 +200,6 @@ def register():
|
|||||||
for cls in classes:
|
for cls in classes:
|
||||||
bpy.utils.register_class(cls)
|
bpy.utils.register_class(cls)
|
||||||
|
|
||||||
bpy.types.VIEW3D_MT_edit_mesh_normals.append(menu_func)
|
|
||||||
|
|
||||||
# Unregister Classes & Hotkeys #
|
# Unregister Classes & Hotkeys #
|
||||||
def unregister():
|
def unregister():
|
||||||
@ -223,7 +207,6 @@ def unregister():
|
|||||||
for cls in reversed(classes):
|
for cls in reversed(classes):
|
||||||
bpy.utils.unregister_class(cls)
|
bpy.utils.unregister_class(cls)
|
||||||
|
|
||||||
bpy.types.VIEW3D_MT_edit_mesh_normals.remove(menu_func)
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
register()
|
register()
|
||||||
|
Loading…
Reference in New Issue
Block a user