Pose Library: Update to use the asset shelf (when enabled) #104546

Merged
Julian Eisel merged 33 commits from asset-shelf into main 2023-08-04 15:00:21 +02:00
28 changed files with 470 additions and 203 deletions
Showing only changes of commit 47591deac8 - Show all commits

View File

@ -11,7 +11,7 @@
bl_info = { bl_info = {
"name": "Extra Objects", "name": "Extra Objects",
"author": "Multiple Authors", "author": "Multiple Authors",
"version": (0, 3, 7), "version": (0, 3, 9),
"blender": (2, 80, 0), "blender": (2, 80, 0),
"location": "View3D > Add > Mesh", "location": "View3D > Add > Mesh",
"description": "Add extra mesh object types", "description": "Add extra mesh object types",

View File

@ -294,12 +294,12 @@ def addBrilliant(context, self, s, table_w, crown_h, girdle_t, pavi_d, bezel_f,
bpy.ops.object.mode_set(mode='EDIT', toggle=False) bpy.ops.object.mode_set(mode='EDIT', toggle=False)
bpy.ops.mesh.faces_shade_smooth() bpy.ops.mesh.faces_shade_smooth()
bpy.ops.object.modifier_add(type='EDGE_SPLIT') edge_split_modifier = context.object.modifiers.new("", 'EDGE_SPLIT')
bpy.context.tool_settings.mesh_select_mode = sel_mode bpy.context.tool_settings.mesh_select_mode = sel_mode
bpy.ops.object.mode_set(mode='OBJECT', toggle=False) bpy.ops.object.mode_set(mode='OBJECT', toggle=False)
bpy.ops.object.modifier_apply(modifier="EdgeSplit") bpy.ops.object.modifier_apply(modifier=edge_split_modifier.name)
return dobj return dobj

View File

@ -64,9 +64,7 @@ def Add_Symmetrical_Empty():
sempty.name = "SymmEmpty" sempty.name = "SymmEmpty"
# check if we have a mirror modifier, otherwise add # check if we have a mirror modifier, otherwise add
if (sempty.modifiers and sempty.modifiers['Mirror']): if not any(mod.type == 'MIRROR' for mod in sempty.modifiers):
pass
else:
bpy.ops.object.modifier_add(type='MIRROR') bpy.ops.object.modifier_add(type='MIRROR')
# Delete all! # Delete all!
@ -83,9 +81,7 @@ def Add_Symmetrical_Vert():
sempty.name = "SymmVert" sempty.name = "SymmVert"
# check if we have a mirror modifier, otherwise add # check if we have a mirror modifier, otherwise add
if (sempty.modifiers and sempty.modifiers['Mirror']): if not any(mod.type == 'MIRROR' for mod in sempty.modifiers):
pass
else:
bpy.ops.object.modifier_add(type='MIRROR') bpy.ops.object.modifier_add(type='MIRROR')
# Delete all! # Delete all!
@ -102,7 +98,8 @@ class AddSymmetricalEmpty(Operator):
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
mirror = bpy.context.object.modifiers['Mirror'] mirror = next(mod for mod in bpy.context.object.modifiers
if mod.type == 'MIRROR')
layout.prop(mirror, "use_clip", text="Use Clipping") layout.prop(mirror, "use_clip", text="Use Clipping")
@ -126,7 +123,8 @@ class AddSymmetricalVert(Operator):
def draw(self, context): def draw(self, context):
layout = self.layout layout = self.layout
mirror = bpy.context.object.modifiers['Mirror'] mirror = next(mod for mod in bpy.context.object.modifiers
if mod.type == 'MIRROR')
layout.prop(mirror, "use_clip", text="Use Clipping") layout.prop(mirror, "use_clip", text="Use Clipping")

View File

@ -72,7 +72,7 @@ from amaranth.misc import (
bl_info = { bl_info = {
"name": "Amaranth Toolset", "name": "Amaranth Toolset",
"author": "Pablo Vazquez, Bassam Kurdali, Sergey Sharybin, Lukas Tönne, Cesar Saez, CansecoGPC", "author": "Pablo Vazquez, Bassam Kurdali, Sergey Sharybin, Lukas Tönne, Cesar Saez, CansecoGPC",
"version": (1, 0, 18), "version": (1, 0, 20),
"blender": (3, 2, 0), "blender": (3, 2, 0),
"location": "Everywhere!", "location": "Everywhere!",
"description": "A collection of tools and settings to improve productivity", "description": "A collection of tools and settings to improve productivity",

View File

@ -25,14 +25,16 @@ image_nodes = ("CompositorNodeRLayers",
class AMTH_NODE_OT_show_active_node_image(bpy.types.Operator): class AMTH_NODE_OT_show_active_node_image(bpy.types.Operator):
"""Show active image node image in the image editor""" """Display source image in the Image Editor (if available)"""
bl_idname = "node.show_active_node_image" bl_idname = "node.show_active_node_image"
bl_label = "Preview Image from Node" bl_label = "Open Node Source Image"
bl_options = {"UNDO"} bl_options = {"UNDO"}
@classmethod @classmethod
def poll(cls, context): def poll(cls, context):
return context.space_data == 'NODE_EDITOR' and context.active_node is not None return context.space_data.type == 'NODE_EDITOR' \
and context.active_node is not None \
and context.active_node.bl_idname in image_nodes
def execute(self, context): def execute(self, context):
return {'FINISHED'} return {'FINISHED'}
@ -91,6 +93,17 @@ class AMTH_NODE_OT_show_active_node_image(bpy.types.Operator):
return {"PASS_THROUGH"} return {"PASS_THROUGH"}
def ui(self, context):
node = context.active_node
if node is not None and node.bl_idname in image_nodes:
self.layout.separator()
self.layout.operator_context = 'INVOKE_DEFAULT'
self.layout.operator(
AMTH_NODE_OT_show_active_node_image.bl_idname,
icon="IMAGE", text="Display in Image Editor")
def register(): def register():
bpy.utils.register_class(AMTH_NODE_OT_show_active_node_image) bpy.utils.register_class(AMTH_NODE_OT_show_active_node_image)
kc = bpy.context.window_manager.keyconfigs.addon kc = bpy.context.window_manager.keyconfigs.addon
@ -99,9 +112,15 @@ def register():
"LEFTMOUSE", "DOUBLE_CLICK") "LEFTMOUSE", "DOUBLE_CLICK")
KEYMAPS.append((km, kmi)) KEYMAPS.append((km, kmi))
bpy.types.NODE_MT_node.append(ui)
bpy.types.NODE_MT_context_menu.append(ui)
def unregister(): def unregister():
bpy.utils.unregister_class(AMTH_NODE_OT_show_active_node_image) bpy.utils.unregister_class(AMTH_NODE_OT_show_active_node_image)
for km, kmi in KEYMAPS: for km, kmi in KEYMAPS:
km.keymap_items.remove(kmi) km.keymap_items.remove(kmi)
KEYMAPS.clear() KEYMAPS.clear()
bpy.types.NODE_MT_node.remove(ui)
bpy.types.NODE_MT_context_menu.remove(ui)

View File

@ -11,7 +11,7 @@ bl_info = {
"name": "Archimesh", "name": "Archimesh",
"author": "Antonio Vazquez (antonioya)", "author": "Antonio Vazquez (antonioya)",
"location": "View3D > Add Mesh / Sidebar > Create Tab", "location": "View3D > Add Mesh / Sidebar > Create Tab",
"version": (1, 2, 3), "version": (1, 2, 4),
"blender": (3, 0, 0), "blender": (3, 0, 0),
"description": "Generate rooms, doors, windows, and other architecture objects", "description": "Generate rooms, doors, windows, and other architecture objects",
"doc_url": "{BLENDER_MANUAL_URL}/addons/add_mesh/archimesh.html", "doc_url": "{BLENDER_MANUAL_URL}/addons/add_mesh/archimesh.html",

View File

@ -174,10 +174,9 @@ def set_modifier_solidify(myobject, width):
def set_modifier_boolean(myobject, bolobject): def set_modifier_boolean(myobject, bolobject):
bpy.context.view_layer.objects.active = myobject bpy.context.view_layer.objects.active = myobject
if bpy.context.view_layer.objects.active.name == myobject.name: if bpy.context.view_layer.objects.active.name == myobject.name:
bpy.ops.object.modifier_add(type='BOOLEAN') boolean_modifier = context.object.modifiers.new("", 'BOOLEAN')
mod = myobject.modifiers[len(myobject.modifiers) - 1] boolean_modifier.operation = 'DIFFERENCE'
mod.operation = 'DIFFERENCE' boolean_modifier.object = bolobject
mod.object = bolobject
# -------------------------------------------------------------------- # --------------------------------------------------------------------
@ -709,40 +708,38 @@ def create_brick_material(matname, replace, r, g, b, rv=0.8, gv=0.636, bv=0.315)
nodes = mat.node_tree.nodes nodes = mat.node_tree.nodes
# support for multilanguage # support for multilanguage
node = nodes[get_node_index(nodes, 'BSDF_DIFFUSE')] principled_node = nodes[get_node_index(nodes, 'BSDF_PRINCIPLED')]
node.name = 'Diffuse BSDF'
node.label = 'Diffuse BSDF'
node.inputs[0].default_value = [r, g, b, 1] principled_node.inputs[0].default_value = [r, g, b, 1]
node.location = 500, 160 principled_node.location = 500, 160
node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')] output_node = nodes[get_node_index(nodes, 'OUTPUT_MATERIAL')]
node.location = 700, 160 output_node.location = 700, 160
node = nodes.new('ShaderNodeTexBrick') brick_node = nodes.new('ShaderNodeTexBrick')
node.name = 'Brick_0' brick_node.name = 'Brick_0'
node.inputs[3].default_value = [0.407, 0.411, 0.394, 1] # mortar color brick_node.inputs[3].default_value = [0.407, 0.411, 0.394, 1] # mortar color
node.inputs[4].default_value = 3 # scale brick_node.inputs[4].default_value = 3 # scale
node.inputs[5].default_value = 0.001 # mortar brick_node.inputs[5].default_value = 0.001 # mortar
node.inputs[7].default_value = 0.60 # size_w brick_node.inputs[7].default_value = 0.60 # size_w
node.inputs[8].default_value = 0.30 # size_h brick_node.inputs[8].default_value = 0.30 # size_h
node.location = 300, 160 brick_node.location = 300, 160
node = nodes.new('ShaderNodeRGB') rgb_node = nodes.new('ShaderNodeRGB')
node.name = 'RGB_0' rgb_node.name = 'RGB_0'
node.outputs[0].default_value = [r, g, b, 1] rgb_node.outputs[0].default_value = [r, g, b, 1]
node.location = 70, 160 rgb_node.location = 70, 160
# Connect nodes # Connect nodes
outn = nodes['RGB_0'].outputs['Color'] outn = rgb_node.outputs['Color']
inn = nodes['Brick_0'].inputs['Color1'] inn = brick_node.inputs['Color1']
mat.node_tree.links.new(outn, inn) mat.node_tree.links.new(outn, inn)
inn = nodes['Brick_0'].inputs['Color2'] inn = brick_node.inputs['Color2']
mat.node_tree.links.new(outn, inn) mat.node_tree.links.new(outn, inn)
outn = nodes['Brick_0'].outputs['Color'] outn = brick_node.outputs['Color']
inn = nodes['Diffuse BSDF'].inputs['Color'] inn = principled_node.inputs['Base Color']
mat.node_tree.links.new(outn, inn) mat.node_tree.links.new(outn, inn)
return mat return mat

View File

@ -1,7 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later # SPDX-License-Identifier: GPL-2.0-or-later
import bpy import bpy
import ssl
import urllib.request import urllib.request
import urllib.parse import urllib.parse
import zipfile import zipfile
@ -74,6 +73,7 @@ class GP_OT_install_brush_pack(bpy.types.Operator):
self._append_brushes(Path(self.temp) / blendname) self._append_brushes(Path(self.temp) / blendname)
def execute(self, context): def execute(self, context):
import ssl
import tempfile import tempfile
import os import os

View File

@ -9,6 +9,7 @@ except:
from struct import pack from struct import pack
import array import array
import numpy as np
import zlib import zlib
_BLOCK_SENTINEL_LENGTH = 13 _BLOCK_SENTINEL_LENGTH = 13
@ -112,17 +113,7 @@ class FBXElem:
self.props_type.append(data_types.STRING) self.props_type.append(data_types.STRING)
self.props.append(data) self.props.append(data)
def _add_array_helper(self, data, array_type, prop_type): def _add_array_helper(self, data, prop_type, length):
assert(isinstance(data, array.array))
assert(data.typecode == array_type)
length = len(data)
if _IS_BIG_ENDIAN:
data = data[:]
data.byteswap()
data = data.tobytes()
# mimic behavior of fbxconverter (also common sense) # mimic behavior of fbxconverter (also common sense)
# we could make this configurable. # we could make this configurable.
encoding = 0 if len(data) <= 128 else 1 encoding = 0 if len(data) <= 128 else 1
@ -138,35 +129,78 @@ class FBXElem:
self.props_type.append(prop_type) self.props_type.append(prop_type)
self.props.append(data) self.props.append(data)
def _add_parray_helper(self, data, array_type, prop_type):
assert (isinstance(data, array.array))
assert (data.typecode == array_type)
length = len(data)
if _IS_BIG_ENDIAN:
data = data[:]
data.byteswap()
data = data.tobytes()
self._add_array_helper(data, prop_type, length)
def _add_ndarray_helper(self, data, dtype, prop_type):
assert (isinstance(data, np.ndarray))
assert (data.dtype == dtype)
length = data.size
if _IS_BIG_ENDIAN and data.dtype.isnative:
data = data.byteswap()
data = data.tobytes()
self._add_array_helper(data, prop_type, length)
def add_int32_array(self, data): def add_int32_array(self, data):
if not isinstance(data, array.array): if isinstance(data, np.ndarray):
data = array.array(data_types.ARRAY_INT32, data) self._add_ndarray_helper(data, np.int32, data_types.INT32_ARRAY)
self._add_array_helper(data, data_types.ARRAY_INT32, data_types.INT32_ARRAY) else:
if not isinstance(data, array.array):
data = array.array(data_types.ARRAY_INT32, data)
self._add_parray_helper(data, data_types.ARRAY_INT32, data_types.INT32_ARRAY)
def add_int64_array(self, data): def add_int64_array(self, data):
if not isinstance(data, array.array): if isinstance(data, np.ndarray):
data = array.array(data_types.ARRAY_INT64, data) self._add_ndarray_helper(data, np.int64, data_types.INT64_ARRAY)
self._add_array_helper(data, data_types.ARRAY_INT64, data_types.INT64_ARRAY) else:
if not isinstance(data, array.array):
data = array.array(data_types.ARRAY_INT64, data)
self._add_parray_helper(data, data_types.ARRAY_INT64, data_types.INT64_ARRAY)
def add_float32_array(self, data): def add_float32_array(self, data):
if not isinstance(data, array.array): if isinstance(data, np.ndarray):
data = array.array(data_types.ARRAY_FLOAT32, data) self._add_ndarray_helper(data, np.float32, data_types.FLOAT32_ARRAY)
self._add_array_helper(data, data_types.ARRAY_FLOAT32, data_types.FLOAT32_ARRAY) else:
if not isinstance(data, array.array):
data = array.array(data_types.ARRAY_FLOAT32, data)
self._add_parray_helper(data, data_types.ARRAY_FLOAT32, data_types.FLOAT32_ARRAY)
def add_float64_array(self, data): def add_float64_array(self, data):
if not isinstance(data, array.array): if isinstance(data, np.ndarray):
data = array.array(data_types.ARRAY_FLOAT64, data) self._add_ndarray_helper(data, np.float64, data_types.FLOAT64_ARRAY)
self._add_array_helper(data, data_types.ARRAY_FLOAT64, data_types.FLOAT64_ARRAY) else:
if not isinstance(data, array.array):
data = array.array(data_types.ARRAY_FLOAT64, data)
self._add_parray_helper(data, data_types.ARRAY_FLOAT64, data_types.FLOAT64_ARRAY)
def add_bool_array(self, data): def add_bool_array(self, data):
if not isinstance(data, array.array): if isinstance(data, np.ndarray):
data = array.array(data_types.ARRAY_BOOL, data) self._add_ndarray_helper(data, bool, data_types.BOOL_ARRAY)
self._add_array_helper(data, data_types.ARRAY_BOOL, data_types.BOOL_ARRAY) else:
if not isinstance(data, array.array):
data = array.array(data_types.ARRAY_BOOL, data)
self._add_parray_helper(data, data_types.ARRAY_BOOL, data_types.BOOL_ARRAY)
def add_byte_array(self, data): def add_byte_array(self, data):
if not isinstance(data, array.array): if isinstance(data, np.ndarray):
data = array.array(data_types.ARRAY_BYTE, data) self._add_ndarray_helper(data, np.byte, data_types.BYTE_ARRAY)
self._add_array_helper(data, data_types.ARRAY_BYTE, data_types.BYTE_ARRAY) else:
if not isinstance(data, array.array):
data = array.array(data_types.ARRAY_BYTE, data)
self._add_parray_helper(data, data_types.ARRAY_BYTE, data_types.BYTE_ARRAY)
# ------------------------- # -------------------------
# internal helper functions # internal helper functions

View File

@ -6,6 +6,7 @@
import array import array
import datetime import datetime
import math import math
import numpy as np
import os import os
import time import time
@ -46,9 +47,9 @@ from .fbx_utils import (
# Miscellaneous utils. # Miscellaneous utils.
PerfMon, PerfMon,
units_blender_to_fbx_factor, units_convertor, units_convertor_iter, units_blender_to_fbx_factor, units_convertor, units_convertor_iter,
matrix4_to_array, similar_values, similar_values_iter, matrix4_to_array, similar_values, similar_values_iter, astype_view_signedness, fast_first_axis_unique,
# Mesh transform helpers. # Mesh transform helpers.
vcos_transformed_gen, nors_transformed_gen, vcos_transformed_gen, nors_transformed_gen, vcos_transformed, nors_transformed,
# UUID from key. # UUID from key.
get_fbx_uuid_from_key, get_fbx_uuid_from_key,
# Key generators. # Key generators.
@ -884,9 +885,11 @@ def fbx_data_mesh_elements(root, me_obj, scene_data, done_meshes):
elem_data_single_int32(geom, b"GeometryVersion", FBX_GEOMETRY_VERSION) elem_data_single_int32(geom, b"GeometryVersion", FBX_GEOMETRY_VERSION)
# Vertex cos. # Vertex cos.
t_co = array.array(data_types.ARRAY_FLOAT64, (0.0,)) * len(me.vertices) * 3 co_bl_dtype = np.single
co_fbx_dtype = np.float64
t_co = np.empty(len(me.vertices) * 3, dtype=co_bl_dtype)
me.vertices.foreach_get("co", t_co) me.vertices.foreach_get("co", t_co)
elem_data_single_float64_array(geom, b"Vertices", chain(*vcos_transformed_gen(t_co, geom_mat_co))) elem_data_single_float64_array(geom, b"Vertices", vcos_transformed(t_co, geom_mat_co, co_fbx_dtype))
del t_co del t_co
# Polygon indices. # Polygon indices.

View File

@ -9,6 +9,7 @@ import time
from collections import namedtuple from collections import namedtuple
from collections.abc import Iterable from collections.abc import Iterable
from itertools import zip_longest, chain from itertools import zip_longest, chain
import numpy as np
import bpy import bpy
import bpy_extras import bpy_extras
@ -272,6 +273,246 @@ def nors_transformed_gen(raw_nors, m=None):
return gen if m is None else (m @ Vector(v) for v in gen) return gen if m is None else (m @ Vector(v) for v in gen)
def _mat4_vec3_array_multiply(mat4, vec3_array, dtype=None, return_4d=False):
"""Multiply a 4d matrix by each 3d vector in an array and return as an array of either 3d or 4d vectors.
A view of the input array is returned if return_4d=False, the dtype matches the input array and either the matrix is
None or, ignoring the last row, is a 3x3 identity matrix with no translation:
1, 0, 0, 0
0, 1, 0, 0
0, 0, 1, 0
When dtype=None, it defaults to the dtype of the input array."""
return_dtype = dtype if dtype is not None else vec3_array.dtype
vec3_array = vec3_array.reshape(-1, 3)
# Multiplying a 4d mathutils.Matrix by a 3d mathutils.Vector implicitly extends the Vector to 4d during the
# calculation by appending 1.0 to the Vector and then the 4d result is truncated back to 3d.
# Numpy does not do an implicit extension to 4d, so it would have to be done explicitly by extending the entire
# vec3_array to 4d.
# However, since the w component of the vectors is always 1.0, the last column can be excluded from the
# multiplication and then added to every multiplied vector afterwards, which avoids having to make a 4d copy of
# vec3_array beforehand.
# For a single column vector:
# ┌a, b, c, d┐ ┌x┐ ┌ax+by+cz+d┐
# │e, f, g, h│ @ │y│ = │ex+fy+gz+h│
# │i, j, k, l│ │z│ │ix+jy+kz+l│
# └m, n, o, p┘ └1┘ └mx+ny+oz+p┘
# ┌a, b, c┐ ┌x┐ ┌d┐ ┌ax+by+cz┐ ┌d┐ ┌ax+by+cz+d┐
# │e, f, g│ @ │y│ + │h│ = │ex+fy+gz│ + │h│ = │ex+fy+gz+h│
# │i, j, k│ └z┘ │l│ │ix+jy+kz│ │l│ │ix+jy+kz+l│
# └m, n, o┘ └p┘ └mx+ny+oz┘ └p┘ └mx+ny+oz+p┘
# column_vector_multiplication in mathutils_Vector.c uses double precision math for Matrix @ Vector by casting the
# matrix's values to double precision and then casts back to single precision when returning the result, so at least
# double precision math is always be used to match standard Blender behaviour.
math_precision = np.result_type(np.double, vec3_array)
to_multiply = None
to_add = None
w_to_set = 1.0
if mat4 is not None:
mat_np = np.array(mat4, dtype=math_precision)
# Identity matrix is compared against to check if any matrix multiplication is required.
identity = np.identity(4, dtype=math_precision)
if not return_4d:
# If returning 3d, the entire last row of the matrix can be ignored because it only affects the w component.
mat_np = mat_np[:3]
identity = identity[:3]
# Split mat_np into the columns to multiply and the column to add afterwards.
# First 3 columns
multiply_columns = mat_np[:, :3]
multiply_identity = identity[:, :3]
# Last column only
add_column = mat_np.T[3]
# Analyze the split parts of the matrix to figure out if there is anything to multiply and anything to add.
if not np.array_equal(multiply_columns, multiply_identity):
to_multiply = multiply_columns
if return_4d and to_multiply is None:
# When there's nothing to multiply, the w component of add_column can be set directly into the array because
# mx+ny+oz+p becomes 0x+0y+0z+p where p is add_column[3].
w_to_set = add_column[3]
# Replace add_column with a view of only the translation.
add_column = add_column[:3]
if add_column.any():
to_add = add_column
if to_multiply is None:
# If there's anything to add, ensure it's added using the precision being used for math.
array_dtype = math_precision if to_add is not None else return_dtype
if return_4d:
multiplied_vectors = np.empty((len(vec3_array), 4), dtype=array_dtype)
multiplied_vectors[:, :3] = vec3_array
multiplied_vectors[:, 3] = w_to_set
else:
# If there's anything to add, ensure a copy is made so that the input vec3_array isn't modified.
multiplied_vectors = vec3_array.astype(array_dtype, copy=to_add is not None)
else:
# Matrix multiplication has the signature (n,k) @ (k,m) -> (n,m).
# Where v is the number of vectors in vec3_array and d is the number of vector dimensions to return:
# to_multiply has shape (d,3), vec3_array has shape (v,3) and the result should have shape (v,d).
# Either vec3_array or to_multiply must be transposed:
# Can transpose vec3_array and then transpose the result:
# (v,3).T -> (3,v); (d,3) @ (3,v) -> (d,v); (d,v).T -> (v,d)
# Or transpose to_multiply and swap the order of multiplication:
# (d,3).T -> (3,d); (v,3) @ (3,d) -> (v,d)
# There's no, or negligible, performance difference between the two options, however, the result of the latter
# will be C contiguous in memory, making it faster to convert to flattened bytes with .tobytes().
multiplied_vectors = vec3_array @ to_multiply.T
if to_add is not None:
for axis, to_add_to_axis in zip(multiplied_vectors.T, to_add):
if to_add_to_axis != 0:
axis += to_add_to_axis
# Cast to the desired return type before returning.
return multiplied_vectors.astype(return_dtype, copy=False)
def vcos_transformed(raw_cos, m=None, dtype=None):
return _mat4_vec3_array_multiply(m, raw_cos, dtype)
def nors_transformed(raw_nors, m=None, dtype=None):
# Great, now normals are also expected 4D!
# XXX Back to 3D normals for now!
# return _mat4_vec3_array_multiply(m, raw_nors, dtype, return_4d=True)
return _mat4_vec3_array_multiply(m, raw_nors, dtype)
def astype_view_signedness(arr, new_dtype):
"""Unsafely views arr as new_dtype if the itemsize and byteorder of arr matches but the signedness does not,
otherwise calls np.ndarray.astype with copy=False.
The benefit of copy=False is that if the array can be safely viewed as the new type, then a view is made, instead of
a copy with the new type.
Unsigned types can't be viewed safely as signed or vice-versa, meaning that a copy would always be made by
.astype(..., copy=False).
This is intended for viewing uintc data (a common Blender C type with variable itemsize, though usually 4 bytes, so
uint32) as int32 (a common FBX type), when the itemsizes match."""
arr_dtype = arr.dtype
if not isinstance(new_dtype, np.dtype):
# new_dtype could be a type instance or a string, but it needs to be a dtype to compare its itemsize, byteorder
# and kind.
new_dtype = np.dtype(new_dtype)
# For simplicity, only dtypes of the same itemsize and byteorder, but opposite signedness, are handled. Everything
# else is left to .astype.
arr_kind = arr_dtype.kind
new_kind = new_dtype.kind
if (
# Signed and unsigned int are opposite in terms of signedness. Other types don't have signedness.
((arr_kind == 'i' and new_kind == 'u') or (arr_kind == 'u' and new_kind == 'i'))
and arr_dtype.itemsize == new_dtype.itemsize
and arr_dtype.byteorder == new_dtype.byteorder
):
# new_dtype has opposite signedness and matching itemsize and byteorder, so return a view of the new type.
return arr.view(new_dtype)
else:
return arr.astype(new_dtype, copy=False)
def fast_first_axis_flat(ar):
"""Get a flat view (or a copy if a view is not possible) of the input array whereby each element is a single element
of a dtype that is fast to sort, sorts according to individual bytes and contains the data for an entire row (and
any further dimensions) of the input array.
Since the dtype of the view could sort in a different order to the dtype of the input array, this isn't typically
useful for actual sorting, but it is useful for sorting-based uniqueness, such as np.unique."""
# If there are no rows, each element will be viewed as the new dtype.
elements_per_row = math.prod(ar.shape[1:])
row_itemsize = ar.itemsize * elements_per_row
# Get a dtype with itemsize that equals row_itemsize.
# Integer types sort the fastest, but are only available for specific itemsizes.
uint_dtypes_by_itemsize = {1: np.uint8, 2: np.uint16, 4: np.uint32, 8: np.uint64}
# Signed/unsigned makes no noticeable speed difference, but using unsigned will result in ordering according to
# individual bytes like the other, non-integer types.
if row_itemsize in uint_dtypes_by_itemsize:
entire_row_dtype = uint_dtypes_by_itemsize[row_itemsize]
else:
# When using kind='stable' sorting, numpy only uses radix sort with integer types, but it's still
# significantly faster to sort by a single item per row instead of multiple row elements or multiple structured
# type fields.
# Construct a flexible size dtype with matching itemsize.
# Should always be 4 because each character in a unicode string is UCS4.
str_itemsize = np.dtype((np.str_, 1)).itemsize
if row_itemsize % str_itemsize == 0:
# Unicode strings seem to be slightly faster to sort than bytes.
entire_row_dtype = np.dtype((np.str_, row_itemsize // str_itemsize))
else:
# Bytes seem to be slightly faster to sort than raw bytes (np.void).
entire_row_dtype = np.dtype((np.bytes_, row_itemsize))
# View each element along the first axis as a single element.
# View (or copy if a view is not possible) as flat
ar = ar.reshape(-1)
# To view as a dtype of different size, the last axis (entire array in NumPy 1.22 and earlier) must be C-contiguous.
if row_itemsize != ar.itemsize and not ar.flags.c_contiguous:
ar = np.ascontiguousarray(ar)
return ar.view(entire_row_dtype)
def fast_first_axis_unique(ar, return_unique=True, return_index=False, return_inverse=False, return_counts=False):
"""np.unique with axis=0 but optimised for when the input array has multiple elements per row, and the returned
unique array doesn't need to be sorted.
Arrays with more than one element per row are more costly to sort in np.unique due to being compared one
row-element at a time, like comparing tuples.
By viewing each entire row as a single non-structured element, much faster sorting can be achieved. Since the values
are viewed as a different type to their original, this means that the returned array of unique values may not be
sorted according to their original type.
The array of unique values can be excluded from the returned tuple by specifying return_unique=False.
Float type caveats:
All elements of -0.0 in the input array will be replaced with 0.0 to ensure that both values are collapsed into one.
NaN values can have lots of different byte representations (e.g. signalling/quiet and custom payloads). Only the
duplicates of each unique byte representation will be collapsed into one."""
# At least something should always be returned.
assert(return_unique or return_index or return_inverse or return_counts)
# Only signed integer, unsigned integer and floating-point kinds of data are allowed. Other kinds of data have not
# been tested.
assert(ar.dtype.kind in "iuf")
# Floating-point types have different byte representations for -0.0 and 0.0. Collapse them together by replacing all
# -0.0 in the input array with 0.0.
if ar.dtype.kind == 'f':
ar[ar == -0.0] = 0.0
# It's a bit annoying that the unique array is always calculated even when it might not be needed, but it is
# generally insignificant compared to the cost of sorting.
result = np.unique(fast_first_axis_flat(ar), return_index=return_index,
return_inverse=return_inverse, return_counts=return_counts)
if return_unique:
unique = result[0] if isinstance(result, tuple) else result
# View in the original dtype.
unique = unique.view(ar.dtype)
# Return the same number of elements per row and any extra dimensions per row as the input array.
unique.shape = (-1, *ar.shape[1:])
if isinstance(result, tuple):
return (unique,) + result[1:]
else:
return unique
else:
# Remove the first element, the unique array.
result = result[1:]
if len(result) == 1:
# Unpack single element tuples.
return result[0]
else:
return result
# ##### UIDs code. ##### # ##### UIDs code. #####
# ID class (mere int). # ID class (mere int).

View File

@ -11,7 +11,7 @@ bl_info = {
"name": "Auto Mirror", "name": "Auto Mirror",
"description": "Super fast cutting and mirroring for mesh", "description": "Super fast cutting and mirroring for mesh",
"author": "Lapineige", "author": "Lapineige",
"version": (2, 5, 3), "version": (2, 5, 4),
"blender": (2, 80, 0), "blender": (2, 80, 0),
"location": "View 3D > Sidebar > Edit Tab > AutoMirror (panel)", "location": "View 3D > Sidebar > Edit Tab > AutoMirror (panel)",
"warning": "", "warning": "",
@ -187,12 +187,13 @@ class AutoMirror(bpy.types.Operator):
bpy.ops.object.mode_set(mode = current_mode) # Reload previous mode bpy.ops.object.mode_set(mode = current_mode) # Reload previous mode
if automirror.cut: if automirror.cut:
bpy.ops.object.modifier_add(type = 'MIRROR') # Add a mirror modifier # Add a mirror modifier
bpy.context.object.modifiers[-1].use_axis[0] = X # Choose the axis to use, based on the cut's axis mirror_modifier = bpy.context.object.modifiers.new("", 'MIRROR')
bpy.context.object.modifiers[-1].use_axis[1] = Y mirror_modifier.use_axis[0] = X # Choose the axis to use, based on the cut's axis
bpy.context.object.modifiers[-1].use_axis[2] = Z mirror_modifier.use_axis[1] = Y
bpy.context.object.modifiers[-1].use_clip = automirror.Use_Matcap mirror_modifier.use_axis[2] = Z
bpy.context.object.modifiers[-1].show_on_cage = automirror.show_on_cage mirror_modifier.use_clip = automirror.Use_Matcap
mirror_modifier.show_on_cage = automirror.show_on_cage
if automirror.apply_mirror: if automirror.apply_mirror:
bpy.ops.object.mode_set(mode = 'OBJECT') bpy.ops.object.mode_set(mode = 'OBJECT')
bpy.ops.object.modifier_apply(modifier = bpy.context.object.modifiers[-1].name) bpy.ops.object.modifier_apply(modifier = bpy.context.object.modifiers[-1].name)

View File

@ -76,8 +76,12 @@ class VIEW3D_PT_tools_SURFSK_mesh(Panel):
except: pass except: pass
try: col.prop(mesh_object.data.materials[0], "diffuse_color") try: col.prop(mesh_object.data.materials[0], "diffuse_color")
except: pass except: pass
try: col.prop(mesh_object.modifiers['Shrinkwrap'], "offset") try:
except: pass shrinkwrap = next(mod for mod in mesh_object.modifiers
if mod.type == 'SHRINKWRAP')
col.prop(shrinkwrap, "offset")
except:
pass
try: col.prop(mesh_object, "show_in_front") try: col.prop(mesh_object, "show_in_front")
except: pass except: pass
try: col.prop(bs, "SURFSK_shade_smooth") try: col.prop(bs, "SURFSK_shade_smooth")
@ -1652,8 +1656,7 @@ class MESH_OT_SURFSK_add_surface(Operator):
final_ob_duplicate = bpy.context.view_layer.objects.active final_ob_duplicate = bpy.context.view_layer.objects.active
bpy.ops.object.modifier_add('INVOKE_REGION_WIN', type='SHRINKWRAP') shrinkwrap_modifier = context.object.modifiers.new("", 'SHRINKWRAP')
shrinkwrap_modifier = final_ob_duplicate.modifiers[-1]
shrinkwrap_modifier.wrap_method = "NEAREST_VERTEX" shrinkwrap_modifier.wrap_method = "NEAREST_VERTEX"
shrinkwrap_modifier.target = self.main_object shrinkwrap_modifier.target = self.main_object
@ -3514,8 +3517,7 @@ class MESH_OT_SURFSK_init(Operator):
color_red = [1.0, 0.0, 0.0, 0.3] color_red = [1.0, 0.0, 0.0, 0.3]
material = makeMaterial("BSurfaceMesh", color_red) material = makeMaterial("BSurfaceMesh", color_red)
mesh_object.data.materials.append(material) mesh_object.data.materials.append(material)
bpy.ops.object.modifier_add(type='SHRINKWRAP') modifier = mesh_object.modifiers.new("", 'SHRINKWRAP')
modifier = mesh_object.modifiers["Shrinkwrap"]
if self.active_object is not None: if self.active_object is not None:
modifier.target = self.active_object modifier.target = self.active_object
modifier.wrap_method = 'TARGET_PROJECT' modifier.wrap_method = 'TARGET_PROJECT'
@ -3593,44 +3595,36 @@ class MESH_OT_SURFSK_add_modifiers(Operator):
bpy.context.view_layer.objects.active = mesh_object bpy.context.view_layer.objects.active = mesh_object
try: try:
shrinkwrap = mesh_object.modifiers["Shrinkwrap"] shrinkwrap = next(mod for mod in mesh_object.modifiers
if self.active_object is not None and self.active_object != mesh_object: if mod.type == 'SHRINKWRAP')
shrinkwrap.target = self.active_object
shrinkwrap.wrap_method = 'TARGET_PROJECT'
shrinkwrap.wrap_mode = 'OUTSIDE_SURFACE'
shrinkwrap.show_on_cage = True
shrinkwrap.offset = bpy.context.scene.bsurfaces.SURFSK_Shrinkwrap_offset
except: except:
bpy.ops.object.modifier_add(type='SHRINKWRAP') shrinkwrap = mesh_object.modifiers.new("", 'SHRINKWRAP')
shrinkwrap = mesh_object.modifiers["Shrinkwrap"] if self.active_object is not None and self.active_object != mesh_object:
if self.active_object is not None and self.active_object != mesh_object: shrinkwrap.target = self.active_object
shrinkwrap.target = self.active_object shrinkwrap.wrap_method = 'TARGET_PROJECT'
shrinkwrap.wrap_method = 'TARGET_PROJECT' shrinkwrap.wrap_mode = 'OUTSIDE_SURFACE'
shrinkwrap.wrap_mode = 'OUTSIDE_SURFACE' shrinkwrap.show_on_cage = True
shrinkwrap.show_on_cage = True shrinkwrap.offset = bpy.context.scene.bsurfaces.SURFSK_Shrinkwrap_offset
shrinkwrap.offset = bpy.context.scene.bsurfaces.SURFSK_Shrinkwrap_offset
try: try:
mirror = mesh_object.modifiers["Mirror"] mirror = next(mod for mod in mesh_object.modifiers
mirror.use_clip = True if mod.type == 'MIRROR')
except: except:
bpy.ops.object.modifier_add(type='MIRROR') mirror = mesh_object.modifiers.new("", 'MIRROR')
mirror = mesh_object.modifiers["Mirror"] mirror.use_clip = True
mirror.use_clip = True
try: try:
_subsurf = mesh_object.modifiers["Subdivision"] _subsurf = next(mod for mod in mesh_object.modifiers
if mod.type == 'SUBSURF')
except: except:
bpy.ops.object.modifier_add(type='SUBSURF') _subsurf = mesh_object.modifiers.new("", 'SUBSURF')
_subsurf = mesh_object.modifiers["Subdivision"]
try: try:
solidify = mesh_object.modifiers["Solidify"] solidify = next(mod for mod in mesh_object.modifiers
solidify.thickness = 0.01 if mod.type == 'SOLIDIFY')
except: except:
bpy.ops.object.modifier_add(type='SOLIDIFY') solidify = mesh_object.modifiers.new("", 'SOLIDIFY')
solidify = mesh_object.modifiers["Solidify"] solidify.thickness = 0.01
solidify.thickness = 0.01
return {"FINISHED"} return {"FINISHED"}
@ -3960,10 +3954,10 @@ class CURVE_OT_SURFSK_reorder_splines(Operator):
curves_duplicate_2.select_set(True) curves_duplicate_2.select_set(True)
bpy.context.view_layer.objects.active = curves_duplicate_2 bpy.context.view_layer.objects.active = curves_duplicate_2
bpy.ops.object.modifier_add('INVOKE_REGION_WIN', type='SHRINKWRAP') shrinkwrap = curves_duplicate_2.modifiers.new("", 'SHRINKWRAP')
curves_duplicate_2.modifiers["Shrinkwrap"].wrap_method = "NEAREST_VERTEX" shrinkwrap.wrap_method = "NEAREST_VERTEX"
curves_duplicate_2.modifiers["Shrinkwrap"].target = GP_strokes_mesh shrinkwrap.target = GP_strokes_mesh
bpy.ops.object.modifier_apply('INVOKE_REGION_WIN', modifier='Shrinkwrap') bpy.ops.object.modifier_apply('INVOKE_REGION_WIN', modifier=shrinkwrap.name)
# Get the distance of each vert from its original position to its position with Shrinkwrap # Get the distance of each vert from its original position to its position with Shrinkwrap
nearest_points_coords = {} nearest_points_coords = {}

View File

@ -17,7 +17,7 @@
bl_info = { bl_info = {
"name": "Tissue", "name": "Tissue",
"author": "Alessandro Zomparelli (Co-de-iT)", "author": "Alessandro Zomparelli (Co-de-iT)",
"version": (0, 3, 52), "version": (0, 3, 54),
"blender": (2, 93, 0), "blender": (2, 93, 0),
"location": "", "location": "",
"description": "Tools for Computational Design", "description": "Tools for Computational Design",

View File

@ -13,7 +13,7 @@ class tissuePreferences(bpy.types.AddonPreferences):
print_stats : IntProperty( print_stats : IntProperty(
name="Print Stats", name="Print Stats",
description="Print in the console all details about the computing time.", description="Print in the console all details about the computing time",
default=1, default=1,
min=0, min=0,
max=4 max=4

View File

@ -65,7 +65,7 @@ class tissue_to_curve_prop(PropertyGroup):
) )
bool_lock : BoolProperty( bool_lock : BoolProperty(
name="Lock", name="Lock",
description="Prevent automatic update on settings changes or if other objects have it in the hierarchy.", description="Prevent automatic update on settings changes or if other objects have it in the hierarchy",
default=False, default=False,
update = anim_curve_active update = anim_curve_active
) )
@ -77,7 +77,7 @@ class tissue_to_curve_prop(PropertyGroup):
) )
bool_run : BoolProperty( bool_run : BoolProperty(
name="Animatable Curve", name="Animatable Curve",
description="Automatically recompute the conversion when the frame is changed.", description="Automatically recompute the conversion when the frame is changed",
default = False default = False
) )
use_modifiers : BoolProperty( use_modifiers : BoolProperty(

View File

@ -228,14 +228,10 @@ class dual_mesh(Operator):
) )
bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.mesh.select_all(action='DESELECT')
bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.modifier_add(type='SUBSURF') subsurf_modifier = context.object.modifiers.new("dual_mesh_subsurf", 'SUBSURF')
ob.modifiers[-1].name = "dual_mesh_subsurf" context.object.modifiers.move(len(context.object.modifiers)-1, 0)
while True:
bpy.ops.object.modifier_move_up(modifier="dual_mesh_subsurf")
if ob.modifiers[0].name == "dual_mesh_subsurf":
break
bpy.ops.object.modifier_apply(modifier='dual_mesh_subsurf') bpy.ops.object.modifier_apply(modifier=subsurf_modifier.name)
bpy.ops.object.mode_set(mode='EDIT') bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.mesh.select_all(action='DESELECT')

View File

@ -371,8 +371,8 @@ class lattice_along_surface(Operator):
lattice.scale.z = 1 lattice.scale.z = 1
context.view_layer.objects.active = obj context.view_layer.objects.active = obj
bpy.ops.object.modifier_add(type='LATTICE') lattice_modifier = context.object.modifiers.new("", 'LATTICE')
obj.modifiers[-1].object = lattice lattice_modifier.object = lattice
# set as parent # set as parent
if self.set_parent: if self.set_parent:
@ -433,7 +433,7 @@ class lattice_along_surface(Operator):
bpy.ops.object.delete(use_global=False) bpy.ops.object.delete(use_global=False)
context.view_layer.objects.active = obj context.view_layer.objects.active = obj
obj.select_set(True) obj.select_set(True)
bpy.ops.object.modifier_remove(modifier=obj.modifiers[-1].name) bpy.ops.object.modifier_remove(modifier=lattice_modifier.name)
if nu > 64 or nv > 64: if nu > 64 or nv > 64:
self.report({'ERROR'}, "Maximum resolution allowed for Lattice is 64") self.report({'ERROR'}, "Maximum resolution allowed for Lattice is 64")
return {'CANCELLED'} return {'CANCELLED'}

View File

@ -1780,7 +1780,7 @@ class tissue_update_tessellate_deps(Operator):
bl_idname = "object.tissue_update_tessellate_deps" bl_idname = "object.tissue_update_tessellate_deps"
bl_label = "Tissue Refresh" bl_label = "Tissue Refresh"
bl_description = ("Fast update the tessellated mesh according to base and " bl_description = ("Fast update the tessellated mesh according to base and "
"component changes.") "component changes")
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
go = False go = False

View File

@ -188,7 +188,7 @@ def set_tessellate_handler(self, context):
class tissue_prop(PropertyGroup): class tissue_prop(PropertyGroup):
bool_lock : BoolProperty( bool_lock : BoolProperty(
name="Lock", name="Lock",
description="Prevent automatic update on settings changes or if other objects have it in the hierarchy.", description="Prevent automatic update on settings changes or if other objects have it in the hierarchy",
default=False default=False
) )
bool_dependencies : BoolProperty( bool_dependencies : BoolProperty(

View File

@ -917,8 +917,10 @@ class reaction_diffusion(Operator):
class edges_deformation(Operator): class edges_deformation(Operator):
bl_idname = "object.edges_deformation" bl_idname = "object.edges_deformation"
bl_label = "Edges Deformation" bl_label = "Edges Deformation"
bl_description = ("Compute Weight based on the deformation of edges"+ bl_description = (
"according to visible modifiers.") "Compute Weight based on the deformation of edges "
"according to visible modifiers"
)
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
bounds : EnumProperty( bounds : EnumProperty(
@ -1061,8 +1063,10 @@ class edges_deformation(Operator):
class edges_bending(Operator): class edges_bending(Operator):
bl_idname = "object.edges_bending" bl_idname = "object.edges_bending"
bl_label = "Edges Bending" bl_label = "Edges Bending"
bl_description = ("Compute Weight based on the bending of edges"+ bl_description = (
"according to visible modifiers.") "Compute Weight based on the bending of edges"
"according to visible modifiers"
)
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
bounds : EnumProperty( bounds : EnumProperty(
@ -1455,10 +1459,10 @@ class weight_contour_displace(Operator):
# Displace Modifier # Displace Modifier
if self.bool_displace: if self.bool_displace:
ob.modifiers.new(type='DISPLACE', name='Displace') displace_modifier = ob.modifiers.new(type='DISPLACE', name='Displace')
ob.modifiers["Displace"].mid_level = 0 displace_modifier.mid_level = 0
ob.modifiers["Displace"].strength = 0.1 displace_modifier.strength = 0.1
ob.modifiers['Displace'].vertex_group = vertex_group_name displace_modifier.vertex_group = vertex_group_name
bpy.ops.object.mode_set(mode='EDIT') bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.object.mode_set(mode='WEIGHT_PAINT') bpy.ops.object.mode_set(mode='WEIGHT_PAINT')
@ -2128,7 +2132,7 @@ class tissue_weight_contour_curves_pattern(Operator):
spiralized: BoolProperty( spiralized: BoolProperty(
name='Spiralized', default=False, name='Spiralized', default=False,
description='Create a Spiral Contour. Works better with dense meshes.' description='Create a Spiral Contour. Works better with dense meshes'
) )
spiral_axis: FloatVectorProperty( spiral_axis: FloatVectorProperty(
name="Spiral Axis", default=(0,0,1), name="Spiral Axis", default=(0,0,1),
@ -2392,7 +2396,7 @@ class vertex_colors_to_vertex_groups(Operator):
bl_idname = "object.vertex_colors_to_vertex_groups" bl_idname = "object.vertex_colors_to_vertex_groups"
bl_label = "Vertex Color" bl_label = "Vertex Color"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
bl_description = ("Convert the active Vertex Color into a Vertex Group.") bl_description = ("Convert the active Vertex Color into a Vertex Group")
red : BoolProperty( red : BoolProperty(
name="red channel", default=False, description="convert red channel") name="red channel", default=False, description="convert red channel")
@ -2486,7 +2490,7 @@ class vertex_group_to_vertex_colors(Operator):
bl_idname = "object.vertex_group_to_vertex_colors" bl_idname = "object.vertex_group_to_vertex_colors"
bl_label = "Vertex Group" bl_label = "Vertex Group"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
bl_description = ("Convert the active Vertex Group into a Vertex Color.") bl_description = ("Convert the active Vertex Group into a Vertex Color")
channel : EnumProperty( channel : EnumProperty(
items=[('BLUE', 'Blue Channel', 'Convert to Blue Channel'), items=[('BLUE', 'Blue Channel', 'Convert to Blue Channel'),
@ -2579,7 +2583,7 @@ class vertex_group_to_uv(Operator):
bl_idname = "object.vertex_group_to_uv" bl_idname = "object.vertex_group_to_uv"
bl_label = "Vertex Group" bl_label = "Vertex Group"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
bl_description = ("Combine two Vertex Groups as UV Map Layer.") bl_description = ("Combine two Vertex Groups as UV Map Layer")
vertex_group_u : StringProperty( vertex_group_u : StringProperty(
name="U", default='', name="U", default='',
@ -2667,7 +2671,7 @@ class curvature_to_vertex_groups(Operator):
bl_label = "Curvature" bl_label = "Curvature"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
bl_description = ("Generate a Vertex Group based on the curvature of the" bl_description = ("Generate a Vertex Group based on the curvature of the"
"mesh. Is based on Dirty Vertex Color.") "mesh. Is based on Dirty Vertex Color")
invert : BoolProperty( invert : BoolProperty(
name="invert", default=False, description="invert values") name="invert", default=False, description="invert values")
@ -2714,7 +2718,7 @@ class face_area_to_vertex_groups(Operator):
bl_label = "Area" bl_label = "Area"
bl_options = {'REGISTER', 'UNDO'} bl_options = {'REGISTER', 'UNDO'}
bl_description = ("Generate a Vertex Group based on the area of individual" bl_description = ("Generate a Vertex Group based on the area of individual"
"faces.") "faces")
invert : BoolProperty( invert : BoolProperty(
name="invert", default=False, description="invert values") name="invert", default=False, description="invert values")

View File

@ -4,7 +4,7 @@ bl_info = {
"name": "Carver", "name": "Carver",
"author": "Pixivore, Cedric LEPILLER, Ted Milker, Clarkx", "author": "Pixivore, Cedric LEPILLER, Ted Milker, Clarkx",
"description": "Multiple tools to carve or to create objects", "description": "Multiple tools to carve or to create objects",
"version": (1, 2, 1), "version": (1, 2, 2),
"blender": (3, 4, 0), "blender": (3, 4, 0),
"location": "3D View > Ctrl/Shift/x", "location": "3D View > Ctrl/Shift/x",
"warning": "", "warning": "",

View File

@ -395,9 +395,9 @@ class CARVER_OT_operator(bpy.types.Operator):
# Set xRay # Set xRay
self.ProfileBrush.show_in_front = True self.ProfileBrush.show_in_front = True
bpy.ops.object.modifier_add(type='SOLIDIFY') solidify_modifier = context.object.modifiers.new("CT_SOLIDIFY",
context.object.modifiers["Solidify"].name = "CT_SOLIDIFY" 'SOLIDIFY')
context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1 solidify_modifier.thickness = 0.1
Selection_Restore(self) Selection_Restore(self)
@ -435,9 +435,9 @@ class CARVER_OT_operator(bpy.types.Operator):
context.view_layer.objects.active = self.ObjectBrush context.view_layer.objects.active = self.ObjectBrush
# Set xRay # Set xRay
self.ObjectBrush.show_in_front = True self.ObjectBrush.show_in_front = True
bpy.ops.object.modifier_add(type='SOLIDIFY') solidify_modifier = context.object.modifiers.new("CT_SOLIDIFY",
context.object.modifiers["Solidify"].name = "CT_SOLIDIFY" 'SOLIDIFY')
context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1 solidify_modifier.thickness = 0.1
#Restore selected and active object #Restore selected and active object
Selection_Restore(self) Selection_Restore(self)
@ -546,10 +546,9 @@ class CARVER_OT_operator(bpy.types.Operator):
# Active le xray # Active le xray
self.ProfileBrush.show_in_front = True self.ProfileBrush.show_in_front = True
bpy.ops.object.modifier_add(type='SOLIDIFY') solidify_modifier = context.object.modifiers.new("CT_SOLIDIFY",
context.object.modifiers["Solidify"].name = "CT_SOLIDIFY" 'SOLIDIFY')
solidify_modifier.thickness = 0.1
context.object.modifiers["CT_SOLIDIFY"].thickness = 0.1
Selection_Restore(self) Selection_Restore(self)

View File

@ -321,8 +321,7 @@ def CreateBevel(context, CurrentObject):
bevel_modifier = True bevel_modifier = True
if bevel_modifier is False: if bevel_modifier is False:
bpy.ops.object.modifier_add(type='BEVEL') mod = context.object.modifiers.new("", 'BEVEL')
mod = context.object.modifiers[-1]
mod.limit_method = 'WEIGHT' mod.limit_method = 'WEIGHT'
mod.width = 0.01 mod.width = 0.01
mod.profile = 0.699099 mod.profile = 0.699099

View File

@ -3,7 +3,7 @@
bl_info = { bl_info = {
"name": "Skinify Rig", "name": "Skinify Rig",
"author": "Albert Makac (karab44)", "author": "Albert Makac (karab44)",
"version": (0, 11, 0), "version": (0, 11, 2),
"blender": (2, 80, 0), "blender": (2, 80, 0),
"location": "Pose Mode > Sidebar > Create Tab", "location": "Pose Mode > Sidebar > Create Tab",
"description": "Creates a mesh object from selected bones", "description": "Creates a mesh object from selected bones",
@ -411,44 +411,28 @@ def generate_mesh(shape_object, size, thickness=0.8, finger_thickness=0.25, sub_
bpy.ops.mesh.select_all(action='DESELECT') bpy.ops.mesh.select_all(action='DESELECT')
# add skin modifier # add skin modifier
shape_object.modifiers.new("Skin", 'SKIN') skin_modifier = shape_object.modifiers.new("Skin", 'SKIN')
bpy.ops.mesh.select_all(action='SELECT') bpy.ops.mesh.select_all(action='SELECT')
override = bpy.context.copy()
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
for region in area.regions:
if region.type == 'WINDOW':
override['area'] = area
override['region'] = region
override['edit_object'] = bpy.context.edit_object
override['scene'] = bpy.context.scene
override['active_object'] = shape_object
override['object'] = shape_object
override['modifier'] = bpy.context.object.modifiers
break
# calculate optimal thickness for defaults # calculate optimal thickness for defaults
bpy.ops.object.skin_root_mark(override) bpy.ops.object.skin_root_mark()
bpy.ops.transform.skin_resize( bpy.ops.transform.skin_resize(
override,
value=(1 * thickness * (size / 10), 1 * thickness * (size / 10), 1 * thickness * (size / 10)), value=(1 * thickness * (size / 10), 1 * thickness * (size / 10), 1 * thickness * (size / 10)),
constraint_axis=(False, False, False), constraint_axis=(False, False, False),
orient_type='GLOBAL', orient_type='GLOBAL',
mirror=False, mirror=False,
use_proportional_edit=False, use_proportional_edit=False,
) )
shape_object.modifiers["Skin"].use_smooth_shade = True skin_modifier.use_smooth_shade = True
shape_object.modifiers["Skin"].use_x_symmetry = True skin_modifier.use_x_symmetry = True
# select finger vertices and calculate optimal thickness for fingers to fix proportions # select finger vertices and calculate optimal thickness for fingers to fix proportions
if len(alternate_scale_idx_list) > 0: if len(alternate_scale_idx_list) > 0:
select_vertices(shape_object, alternate_scale_idx_list) select_vertices(shape_object, alternate_scale_idx_list)
bpy.ops.object.skin_loose_mark_clear(override, action='MARK') bpy.ops.object.skin_loose_mark_clear(action='MARK')
# by default set fingers thickness to 25 percent of body thickness # by default set fingers thickness to 25 percent of body thickness
bpy.ops.transform.skin_resize( bpy.ops.transform.skin_resize(
override,
value=(finger_thickness, finger_thickness, finger_thickness), value=(finger_thickness, finger_thickness, finger_thickness),
constraint_axis=(False, False, False), orient_type='GLOBAL', constraint_axis=(False, False, False), orient_type='GLOBAL',
mirror=False, mirror=False,
@ -478,7 +462,6 @@ def generate_mesh(shape_object, size, thickness=0.8, finger_thickness=0.25, sub_
select_vertices(shape_object, merge_idx) select_vertices(shape_object, merge_idx)
bpy.ops.mesh.merge(type='CENTER') bpy.ops.mesh.merge(type='CENTER')
bpy.ops.transform.skin_resize( bpy.ops.transform.skin_resize(
override,
value=(corrective_thickness, corrective_thickness, corrective_thickness), value=(corrective_thickness, corrective_thickness, corrective_thickness),
constraint_axis=(False, False, False), orient_type='GLOBAL', constraint_axis=(False, False, False), orient_type='GLOBAL',
mirror=False, mirror=False,
@ -492,7 +475,6 @@ def generate_mesh(shape_object, size, thickness=0.8, finger_thickness=0.25, sub_
select_vertices(shape_object, merge_idx) select_vertices(shape_object, merge_idx)
bpy.ops.mesh.merge(type='CENTER') bpy.ops.mesh.merge(type='CENTER')
bpy.ops.transform.skin_resize( bpy.ops.transform.skin_resize(
override,
value=(corrective_thickness, corrective_thickness, corrective_thickness), value=(corrective_thickness, corrective_thickness, corrective_thickness),
constraint_axis=(False, False, False), orient_type='GLOBAL', constraint_axis=(False, False, False), orient_type='GLOBAL',
mirror=False, mirror=False,
@ -507,7 +489,6 @@ def generate_mesh(shape_object, size, thickness=0.8, finger_thickness=0.25, sub_
# change the thickness to make hands look less blocky and more sexy # change the thickness to make hands look less blocky and more sexy
corrective_thickness = 0.7 corrective_thickness = 0.7
bpy.ops.transform.skin_resize( bpy.ops.transform.skin_resize(
override,
value=(corrective_thickness, corrective_thickness, corrective_thickness), value=(corrective_thickness, corrective_thickness, corrective_thickness),
constraint_axis=(False, False, False), orient_type='GLOBAL', constraint_axis=(False, False, False), orient_type='GLOBAL',
mirror=False, mirror=False,
@ -524,19 +505,20 @@ def generate_mesh(shape_object, size, thickness=0.8, finger_thickness=0.25, sub_
if len(root_idx) > 0: if len(root_idx) > 0:
select_vertices(shape_object, root_idx) select_vertices(shape_object, root_idx)
bpy.ops.object.skin_root_mark(override) bpy.ops.object.skin_root_mark()
# skin in edit mode # skin in edit mode
# add Subsurf modifier # add Subsurf modifier
shape_object.modifiers.new("Subsurf", 'SUBSURF') subsurf_modifier = shape_object.modifiers.new("Subsurf", 'SUBSURF')
shape_object.modifiers["Subsurf"].levels = sub_level subsurf_modifier.levels = sub_level
shape_object.modifiers["Subsurf"].render_levels = sub_level subsurf_modifier.render_levels = sub_level
bpy.ops.object.mode_set(mode='OBJECT') bpy.ops.object.mode_set(mode='OBJECT')
bpy.context.view_layer.update()
# object mode apply all modifiers # object mode apply all modifiers
if apply_mod: if apply_mod:
bpy.ops.object.modifier_apply(override, modifier="Skin") bpy.ops.object.modifier_apply(modifier=skin_modifier.name)
bpy.ops.object.modifier_apply(override, modifier="Subsurf") bpy.ops.object.modifier_apply(modifier=subsurf_modifier.name)
return {'FINISHED'} return {'FINISHED'}
@ -624,7 +606,7 @@ def main(context):
ob.scale = oldScale ob.scale = oldScale
ob.select_set(False) ob.select_set(False)
armature_object.select_set(True) armature_object.select_set(True)
scn.objects.active = armature_object context.view_layer.objects.active = armature_object
armature_object.location = oldLocation armature_object.location = oldLocation
armature_object.rotation_euler = oldRotation armature_object.rotation_euler = oldRotation

View File

@ -23,17 +23,17 @@ class POWER_SEQUENCER_OT_speed_up_movie_strip(bpy.types.Operator):
"shortcuts": [ "shortcuts": [
( (
{"type": "TWO", "value": "PRESS", "alt": True}, {"type": "TWO", "value": "PRESS", "alt": True},
{"speed_factor": 2.0}, {"speed_factor": 2},
"Speed x2", "Speed x2",
), ),
( (
{"type": "THREE", "value": "PRESS", "alt": True}, {"type": "THREE", "value": "PRESS", "alt": True},
{"speed_factor": 3.0}, {"speed_factor": 3},
"Speed x3", "Speed x3",
), ),
( (
{"type": "FOUR", "value": "PRESS", "alt": True}, {"type": "FOUR", "value": "PRESS", "alt": True},
{"speed_factor": 4.0}, {"speed_factor": 4},
"Speed x4", "Speed x4",
), ),
], ],

View File

@ -18,7 +18,7 @@ class POWER_SEQUENCER_OT_trim_to_surrounding_cuts(bpy.types.Operator):
little time offset. It's useful after you removed some bad audio but you need to keep some little time offset. It's useful after you removed some bad audio but you need to keep some
video around for a transition. video around for a transition.
By default, the tool leaves a 0.2 seconds margin on either side of the trim. By default, the tool leaves a 0.2 seconds margin on either side of the trim
""" """
doc = { doc = {

View File

@ -8,7 +8,7 @@ from .utils.functions import convert_duration_to_frames
class POWER_SEQUENCER_OT_value_offset(bpy.types.Operator): class POWER_SEQUENCER_OT_value_offset(bpy.types.Operator):
"""Instantly offset selected strips, either using frames or seconds. Allows to """Instantly offset selected strips, either using frames or seconds. Allows to
nudge the selection quickly, using keyboard shortcuts. nudge the selection quickly, using keyboard shortcuts
""" """
doc = { doc = {