Merge branch 'blender-v4.3-release'
This commit is contained in:
@@ -72,14 +72,12 @@ class ShaderScriptImport(bpy.types.Operator, ImportHelper):
|
||||
y -= 20.0
|
||||
return {'FINISHED'}
|
||||
|
||||
"""
|
||||
Use ImportHelper's invoke_popup() to handle the invocation so that this operator's properties
|
||||
are shown in a popup. This allows the user to configure additional settings on the operator like
|
||||
the `set_label` property. Consider having a draw() method on the operator in order to layout the
|
||||
properties in the UI appropriately.
|
||||
|
||||
If filepath information is not provided the file select window will be invoked instead.
|
||||
"""
|
||||
# Use ImportHelper's invoke_popup() to handle the invocation so that this operator's properties
|
||||
# are shown in a popup. This allows the user to configure additional settings on the operator like
|
||||
# the `set_label` property. Consider having a draw() method on the operator in order to layout the
|
||||
# properties in the UI appropriately.
|
||||
#
|
||||
# If filepath information is not provided the file select window will be invoked instead.
|
||||
|
||||
def invoke(self, context, event):
|
||||
return self.invoke_popup(context)
|
||||
|
||||
@@ -1377,14 +1377,13 @@ _ext_manifest_filename_toml = "blender_manifest.toml"
|
||||
|
||||
|
||||
def _extension_module_name_decompose(package):
|
||||
"""
|
||||
Returns the repository module name and the extensions ID from an extensions module name (``__package__``).
|
||||
# Returns the repository module name and the extensions ID from an extensions module name (``__package__``).
|
||||
#
|
||||
# :arg module_name: The extensions module name.
|
||||
# :type module_name: str
|
||||
# :return: (repo_module_name, extension_id)
|
||||
# :rtype: tuple[str, str]
|
||||
|
||||
:arg module_name: The extensions module name.
|
||||
:type module_name: str
|
||||
:return: (repo_module_name, extension_id)
|
||||
:rtype: tuple[str, str]
|
||||
"""
|
||||
if not package.startswith(_ext_base_pkg_idname_with_dot):
|
||||
raise ValueError("The \"package\" does not name an extension")
|
||||
|
||||
|
||||
@@ -308,33 +308,31 @@ class POSE_OT_selection_set_paste(_PoseModeOnlyMixin, Operator):
|
||||
|
||||
|
||||
def _uniqify(name, other_names):
|
||||
"""
|
||||
:arg name: The name to make unique.
|
||||
:type name: str
|
||||
:arg other_names: The name to make unique.
|
||||
:type other_names: str
|
||||
:return: Return a unique name with ``.xxx`` suffix if necessary.
|
||||
:rtype: str
|
||||
|
||||
Example usage:
|
||||
|
||||
>>> _uniqify('hey', ['there'])
|
||||
'hey'
|
||||
>>> _uniqify('hey', ['hey.001', 'hey.005'])
|
||||
'hey'
|
||||
>>> _uniqify('hey', ['hey', 'hey.001', 'hey.005'])
|
||||
'hey.002'
|
||||
>>> _uniqify('hey', ['hey', 'hey.005', 'hey.001'])
|
||||
'hey.002'
|
||||
>>> _uniqify('hey', ['hey', 'hey.005', 'hey.001', 'hey.left'])
|
||||
'hey.002'
|
||||
>>> _uniqify('hey', ['hey', 'hey.001', 'hey.002'])
|
||||
'hey.003'
|
||||
|
||||
It also works with a dict_keys object:
|
||||
>>> _uniqify('hey', {'hey': 1, 'hey.005': 1, 'hey.001': 1}.keys())
|
||||
'hey.002'
|
||||
"""
|
||||
# :arg name: The name to make unique.
|
||||
# :type name: str
|
||||
# :arg other_names: The name to make unique.
|
||||
# :type other_names: str
|
||||
# :return: Return a unique name with ``.xxx`` suffix if necessary.
|
||||
# :rtype: str
|
||||
#
|
||||
# Example usage:
|
||||
#
|
||||
# >>> _uniqify('hey', ['there'])
|
||||
# 'hey'
|
||||
# >>> _uniqify('hey', ['hey.001', 'hey.005'])
|
||||
# 'hey'
|
||||
# >>> _uniqify('hey', ['hey', 'hey.001', 'hey.005'])
|
||||
# 'hey.002'
|
||||
# >>> _uniqify('hey', ['hey', 'hey.005', 'hey.001'])
|
||||
# 'hey.002'
|
||||
# >>> _uniqify('hey', ['hey', 'hey.005', 'hey.001', 'hey.left'])
|
||||
# 'hey.002'
|
||||
# >>> _uniqify('hey', ['hey', 'hey.001', 'hey.002'])
|
||||
# 'hey.003'
|
||||
#
|
||||
# It also works with a dict_keys object:
|
||||
# >>> _uniqify('hey', {'hey': 1, 'hey.005': 1, 'hey.001': 1}.keys())
|
||||
# 'hey.002'
|
||||
|
||||
if name not in other_names:
|
||||
return name
|
||||
@@ -356,14 +354,13 @@ def _uniqify(name, other_names):
|
||||
|
||||
|
||||
def _to_json(context):
|
||||
"""Convert the selected Selection Sets of the current rig to JSON.
|
||||
|
||||
Selected Sets are the active_selection_set determined by the UIList
|
||||
plus any with the is_selected checkbox on.
|
||||
|
||||
:return: The selection as JSON data.
|
||||
:rtype: str
|
||||
"""
|
||||
# Convert the selected Selection Sets of the current rig to JSON.
|
||||
#
|
||||
# Selected Sets are the active_selection_set determined by the UIList
|
||||
# plus any with the is_selected checkbox on.
|
||||
#
|
||||
# :return: The selection as JSON data.
|
||||
# :rtype: str
|
||||
import json
|
||||
|
||||
arm = context.object
|
||||
@@ -379,11 +376,10 @@ def _to_json(context):
|
||||
|
||||
|
||||
def _from_json(context, as_json):
|
||||
"""Add the selection sets (one or more) from JSON to the current rig.
|
||||
|
||||
:arg as_json: The JSON contents to load.
|
||||
:type as_json: str
|
||||
"""
|
||||
# Add the selection sets (one or more) from JSON to the current rig.
|
||||
#
|
||||
# :arg as_json: The JSON contents to load.
|
||||
# :type as_json: str
|
||||
import json
|
||||
|
||||
json_obj = json.loads(as_json)
|
||||
|
||||
@@ -53,18 +53,17 @@ ImageSpec = namedtuple(
|
||||
|
||||
|
||||
def find_image_sequences(files):
|
||||
"""From a group of files, detect image sequences.
|
||||
# From a group of files, detect image sequences.
|
||||
#
|
||||
# This returns a generator of tuples, which contain the filename,
|
||||
# start frame, and length of the detected sequence
|
||||
#
|
||||
# >>> list(find_image_sequences([
|
||||
# ... "test2-001.jp2", "test2-002.jp2",
|
||||
# ... "test3-003.jp2", "test3-004.jp2", "test3-005.jp2", "test3-006.jp2",
|
||||
# ... "blah"]))
|
||||
# [("blah", 1, 1), ("test2-001.jp2", 1, 2), ("test3-003.jp2", 3, 4)]
|
||||
|
||||
This returns a generator of tuples, which contain the filename,
|
||||
start frame, and length of the detected sequence
|
||||
|
||||
>>> list(find_image_sequences([
|
||||
... "test2-001.jp2", "test2-002.jp2",
|
||||
... "test3-003.jp2", "test3-004.jp2", "test3-005.jp2", "test3-006.jp2",
|
||||
... "blah"]))
|
||||
[("blah", 1, 1), ("test2-001.jp2", 1, 2), ("test3-003.jp2", 3, 4)]
|
||||
|
||||
"""
|
||||
from itertools import count
|
||||
import re
|
||||
num_regex = re.compile("[0-9]") # Find a single number.
|
||||
@@ -123,11 +122,10 @@ def find_image_sequences(files):
|
||||
|
||||
|
||||
def load_images(filenames, directory, force_reload=False, frame_start=1, find_sequences=False):
|
||||
"""Wrapper for `bpy_extras.image_utils.load_image`.
|
||||
# Wrapper for `bpy_extras.image_utils.load_image`.
|
||||
|
||||
Loads a set of images, movies, or even image sequences
|
||||
Returns a generator of ImageSpec wrapper objects later used for texture setup
|
||||
"""
|
||||
# Loads a set of images, movies, or even image sequences
|
||||
# Returns a generator of ImageSpec wrapper objects later used for texture setup
|
||||
import os
|
||||
from itertools import repeat
|
||||
from bpy_extras.image_utils import load_image
|
||||
@@ -163,14 +161,13 @@ def load_images(filenames, directory, force_reload=False, frame_start=1, find_se
|
||||
# Position & Size Helpers
|
||||
|
||||
def offset_planes(planes, gap, axis):
|
||||
"""Offset planes from each other by `gap` amount along a _local_ vector `axis`
|
||||
|
||||
For example, offset_planes([obj1, obj2], 0.5, Vector(0, 0, 1)) will place
|
||||
obj2 0.5 blender units away from obj1 along the local positive Z axis.
|
||||
|
||||
This is in local space, not world space, so all planes should share
|
||||
a common scale and rotation.
|
||||
"""
|
||||
# Offset planes from each other by `gap` amount along a _local_ vector `axis`
|
||||
#
|
||||
# For example, offset_planes([obj1, obj2], 0.5, Vector(0, 0, 1)) will place
|
||||
# obj2 0.5 blender units away from obj1 along the local positive Z axis.
|
||||
#
|
||||
# This is in local space, not world space, so all planes should share
|
||||
# a common scale and rotation.
|
||||
prior = planes[0]
|
||||
offset = Vector()
|
||||
for current in planes[1:]:
|
||||
@@ -183,7 +180,7 @@ def offset_planes(planes, gap, axis):
|
||||
|
||||
|
||||
def compute_camera_size(context, center, fill_mode, aspect):
|
||||
"""Determine how large an object needs to be to fit or fill the camera's field of view."""
|
||||
# Determine how large an object needs to be to fit or fill the camera's field of view.
|
||||
scene = context.scene
|
||||
camera = scene.camera
|
||||
view_frame = camera.data.view_frame(scene=scene)
|
||||
@@ -218,7 +215,7 @@ def compute_camera_size(context, center, fill_mode, aspect):
|
||||
|
||||
|
||||
def center_in_camera(camera, ob, axis=(1, 1)):
|
||||
"""Center object along specified axis of the camera"""
|
||||
# Center object along specified axis of the camera.
|
||||
camera_matrix_col = camera.matrix_world.col
|
||||
location = ob.location
|
||||
|
||||
@@ -483,7 +480,8 @@ def create_cycles_material(self, context, img_spec, name):
|
||||
|
||||
|
||||
def get_input_nodes(node, links):
|
||||
"""Get nodes that are a inputs to the given node"""
|
||||
# Get nodes that are a inputs to the given node.
|
||||
|
||||
# Get all links going to node.
|
||||
input_links = {lnk for lnk in links if lnk.to_node == node}
|
||||
# Sort those links, get their input nodes (and avoid doubles!).
|
||||
@@ -505,7 +503,8 @@ def get_input_nodes(node, links):
|
||||
|
||||
|
||||
def auto_align_nodes(node_tree):
|
||||
"""Given a shader node tree, arrange nodes neatly relative to the output node."""
|
||||
# Given a shader node tree, arrange nodes neatly relative to the output node.
|
||||
|
||||
x_gap = 200
|
||||
y_gap = 180
|
||||
nodes = node_tree.nodes
|
||||
@@ -532,10 +531,10 @@ def auto_align_nodes(node_tree):
|
||||
|
||||
|
||||
def clean_node_tree(node_tree):
|
||||
"""Clear all nodes in a shader node tree except the output.
|
||||
# Clear all nodes in a shader node tree except the output.
|
||||
#
|
||||
# Returns the output node
|
||||
|
||||
Returns the output node
|
||||
"""
|
||||
nodes = node_tree.nodes
|
||||
for node in list(nodes): # Copy to avoid altering the loop's data source.
|
||||
if not node.type == 'OUTPUT_MATERIAL':
|
||||
@@ -545,7 +544,7 @@ def clean_node_tree(node_tree):
|
||||
|
||||
|
||||
def get_shadeless_node(dest_node_tree):
|
||||
"""Return a "shadeless" cycles/EEVEE node, creating a node group if nonexistent"""
|
||||
# Return a "shadeless" cycles/EEVEE node, creating a node group if nonexistent.
|
||||
|
||||
# WARNING: using a hard coded name isn't fool proof!
|
||||
# Users could have this name already in a node-tree (albeit unlikely).
|
||||
@@ -742,7 +741,8 @@ class IMAGE_OT_import_as_mesh_planes(AddObjectHelper, ImportHelper, MaterialProp
|
||||
# -----------------
|
||||
# Properties - Size
|
||||
def update_size_mode(self, _context):
|
||||
"""If sizing relative to the camera, always face the camera"""
|
||||
# If sizing relative to the camera, always face the camera.
|
||||
|
||||
if self.size_mode == 'CAMERA':
|
||||
self.prev_align_axis = self.align_axis
|
||||
self.align_axis = 'CAM'
|
||||
@@ -996,7 +996,8 @@ class IMAGE_OT_import_as_mesh_planes(AddObjectHelper, ImportHelper, MaterialProp
|
||||
return plane
|
||||
|
||||
def compute_plane_size(self, context, img_spec):
|
||||
"""Given the image size in pixels and location, determine size of plane"""
|
||||
# Given the image size in pixels and location, determine size of plane.
|
||||
|
||||
px, py = img_spec.size
|
||||
|
||||
# Can't load data.
|
||||
@@ -1026,7 +1027,8 @@ class IMAGE_OT_import_as_mesh_planes(AddObjectHelper, ImportHelper, MaterialProp
|
||||
return x, y
|
||||
|
||||
def align_plane(self, context, plane):
|
||||
"""Pick an axis and align the plane to it"""
|
||||
# Pick an axis and align the plane to it.
|
||||
|
||||
from math import pi
|
||||
if 'CAM' in self.align_axis:
|
||||
# Camera-aligned.
|
||||
|
||||
@@ -20,18 +20,16 @@ from bpy.props import (
|
||||
# Local Utility Functions
|
||||
|
||||
def is_face_uv_selected(face, uv_layer, any_edge):
|
||||
"""
|
||||
Returns True if the face is UV selected.
|
||||
|
||||
:arg face: the face to query.
|
||||
:type face: :class:`BMFace`
|
||||
:arg uv_layer: the UV layer to source UVs from.
|
||||
:type bmesh: :class:`BMLayerItem`
|
||||
:arg any_edge: use edge selection instead of vertex selection.
|
||||
:type any_edge: bool
|
||||
:return: True if the face is UV selected.
|
||||
:rtype: bool
|
||||
"""
|
||||
# Returns True if the face is UV selected.
|
||||
#
|
||||
# :arg face: the face to query.
|
||||
# :type face: :class:`BMFace`
|
||||
# :arg uv_layer: the UV layer to source UVs from.
|
||||
# :type bmesh: :class:`BMLayerItem`
|
||||
# :arg any_edge: use edge selection instead of vertex selection.
|
||||
# :type any_edge: bool
|
||||
# :return: True if the face is UV selected.
|
||||
# :rtype: bool
|
||||
|
||||
if not face.select: # Geometry selection
|
||||
return False
|
||||
@@ -54,18 +52,16 @@ def is_face_uv_selected(face, uv_layer, any_edge):
|
||||
|
||||
|
||||
def is_island_uv_selected(island, uv_layer, any_edge):
|
||||
"""
|
||||
Returns True if the island is UV selected.
|
||||
|
||||
:arg island: list of faces to query.
|
||||
:type island: Sequence[:class:`BMFace`]
|
||||
:arg uv_layer: the UV layer to source UVs from.
|
||||
:type bmesh: :class:`BMLayerItem`
|
||||
:arg any_edge: use edge selection instead of vertex selection.
|
||||
:type any_edge: bool
|
||||
:return: list of lists containing polygon indices.
|
||||
:rtype: bool
|
||||
"""
|
||||
# Returns True if the island is UV selected.
|
||||
#
|
||||
# :arg island: list of faces to query.
|
||||
# :type island: Sequence[:class:`BMFace`]
|
||||
# :arg uv_layer: the UV layer to source UVs from.
|
||||
# :type bmesh: :class:`BMLayerItem`
|
||||
# :arg any_edge: use edge selection instead of vertex selection.
|
||||
# :type any_edge: bool
|
||||
# :return: list of lists containing polygon indices.
|
||||
# :rtype: bool
|
||||
for face in island:
|
||||
if is_face_uv_selected(face, uv_layer, any_edge):
|
||||
return True
|
||||
@@ -73,15 +69,13 @@ def is_island_uv_selected(island, uv_layer, any_edge):
|
||||
|
||||
|
||||
def island_uv_bounds(island, uv_layer):
|
||||
"""
|
||||
The UV bounds of UV island.
|
||||
|
||||
:arg island: list of faces to query.
|
||||
:type island: Sequence[:class:`BMFace`]
|
||||
:arg uv_layer: the UV layer to source UVs from.
|
||||
:return: U-min, V-min, U-max, V-max.
|
||||
:rtype: list[float]
|
||||
"""
|
||||
# The UV bounds of UV island.
|
||||
#
|
||||
# :arg island: list of faces to query.
|
||||
# :type island: Sequence[:class:`BMFace`]
|
||||
# :arg uv_layer: the UV layer to source UVs from.
|
||||
# :return: U-min, V-min, U-max, V-max.
|
||||
# :rtype: list[float]
|
||||
minmax = [1e30, 1e30, -1e30, -1e30]
|
||||
for face in island:
|
||||
for loop in face.loops:
|
||||
@@ -94,15 +88,13 @@ def island_uv_bounds(island, uv_layer):
|
||||
|
||||
|
||||
def island_uv_bounds_center(island, uv_layer):
|
||||
"""
|
||||
The UV bounds center of UV island.
|
||||
|
||||
:arg island: list of faces to query.
|
||||
:type island: Sequence[:class:`BMFace`]
|
||||
:arg uv_layer: the UV layer to source UVs from.
|
||||
:return: U, V center.
|
||||
:rtype: tuple[float, float]
|
||||
"""
|
||||
# The UV bounds center of UV island.
|
||||
#
|
||||
# :arg island: list of faces to query.
|
||||
# :type island: Sequence[:class:`BMFace`]
|
||||
# :arg uv_layer: the UV layer to source UVs from.
|
||||
# :return: U, V center.
|
||||
# :rtype: tuple[float, float]
|
||||
minmax = island_uv_bounds(island, uv_layer)
|
||||
return (
|
||||
(minmax[0] + minmax[2]) / 2.0,
|
||||
|
||||
Reference in New Issue
Block a user