Pose Library: Update to use the asset shelf (when enabled) #104546
@ -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",
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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")
|
||||||
|
|
||||||
|
@ -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",
|
||||||
|
@ -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)
|
||||||
|
@ -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",
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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).
|
||||||
|
@ -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)
|
||||||
|
@ -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 = {}
|
||||||
|
@ -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",
|
||||||
|
@ -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
|
||||||
|
@ -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(
|
||||||
|
@ -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')
|
||||||
|
@ -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'}
|
||||||
|
@ -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
|
||||||
|
@ -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(
|
||||||
|
@ -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")
|
||||||
|
@ -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": "",
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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",
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -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 = {
|
||||||
|
@ -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 = {
|
||||||
|
Loading…
Reference in New Issue
Block a user