Merge branch 'master' into xr-actions-D9124

This commit is contained in:
Peter Kim 2021-03-07 18:50:24 +09:00
commit 0d1b80b5e2
131 changed files with 1721 additions and 946 deletions

View File

@ -19,7 +19,7 @@
bl_info = {
"name": "BlenderKit Online Asset Library",
"author": "Vilem Duha, Petr Dlouhy",
"version": (1, 0, 40),
"version": (2, 92, 0),
"blender": (2, 92, 0),
"location": "View3D > Properties > BlenderKit",
"description": "Online BlenderKit library (materials, models, brushes and more). Connects to the internet.",

File diff suppressed because it is too large Load Diff

View File

@ -303,28 +303,33 @@ class FastRateMenu(Operator):
message: StringProperty(
name="message",
description="message",
default="Rating asset")
default="Rating asset",
options={'SKIP_SAVE'})
asset_id: StringProperty(
name="Asset Base Id",
description="Unique id of the asset (hidden)",
default="")
default="",
options={'SKIP_SAVE'})
asset_name: StringProperty(
name="Asset Name",
description="Name of the asset (hidden)",
default="")
default="",
options={'SKIP_SAVE'})
asset_type: StringProperty(
name="Asset type",
description="asset type",
default="")
default="",
options={'SKIP_SAVE'})
rating_quality: IntProperty(name="Quality",
description="quality of the material",
default=0,
min=-1, max=10,
update=update_ratings_quality)
# update=update_ratings_quality,
options={'SKIP_SAVE'})
# the following enum is only to ease interaction - enums support 'drag over' and enable to draw the stars easily.
rating_quality_ui: EnumProperty(name='rating_quality_ui',
@ -332,12 +337,14 @@ class FastRateMenu(Operator):
description='Rating stars 0 - 10',
default=0,
update=update_quality_ui,
)
options={'SKIP_SAVE'})
rating_work_hours: FloatProperty(name="Work Hours",
description="How many hours did this work take?",
default=0.00,
min=0.0, max=300, update=update_ratings_work_hours
min=0.0, max=300,
# update=update_ratings_work_hours,
options={'SKIP_SAVE'}
)
high_rating_warning = "This is a high rating, please be sure to give such rating only to amazing assets"
@ -363,7 +370,8 @@ class FastRateMenu(Operator):
('200', '200', high_rating_warning),
('250', '250', high_rating_warning),
],
default='0', update=update_ratings_work_hours_ui
default='0', update=update_ratings_work_hours_ui,
options = {'SKIP_SAVE'}
)
rating_work_hours_ui_1_5: EnumProperty(name="Work Hours",
@ -377,7 +385,9 @@ class FastRateMenu(Operator):
('4', '4', ''),
('5', '5', '')
],
default='0', update=update_ratings_work_hours_ui_1_5
default='0',
update=update_ratings_work_hours_ui_1_5,
options = {'SKIP_SAVE'}
)
@classmethod

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -15,7 +15,7 @@
bl_info = {
'name': 'glTF 2.0 format',
'author': 'Julien Duroure, Scurest, Norbert Nopper, Urs Hanselmann, Moritz Becher, Benjamin Schmithüsen, Jim Eckerlein, and many external contributors',
"version": (1, 6, 4),
"version": (1, 6, 8),
'blender': (2, 91, 0),
'location': 'File > Import-Export',
'description': 'Import-Export as glTF 2.0',
@ -196,7 +196,7 @@ class ExportGLTF2_Base:
description='Compression level (0 = most speed, 6 = most compression, higher values currently not supported)',
default=6,
min=0,
max=6
max=10
)
export_draco_position_quantization: IntProperty(
@ -263,6 +263,22 @@ class ExportGLTF2_Base:
default=True
)
use_mesh_edges: BoolProperty(
name='Loose Edges',
description=(
'Export loose edges as lines, using the material from the first material slot'
),
default=False,
)
use_mesh_vertices: BoolProperty(
name='Loose Points',
description=(
'Export loose points as glTF points, using the material from the first material slot'
),
default=False,
)
export_cameras: BoolProperty(
name='Cameras',
description='Export cameras',
@ -440,14 +456,22 @@ class ExportGLTF2_Base:
except Exception:
pass
self.has_active_extenions = len(extension_panel_unregister_functors) > 0
self.has_active_extensions = len(extension_panel_unregister_functors) > 0
return ExportHelper.invoke(self, context, event)
def save_settings(self, context):
# find all export_ props
# find all props to save
exceptional = [
# options that don't start with 'export_'
'use_selection',
'use_mesh_edges',
'use_mesh_vertices',
]
all_props = self.properties
export_props = {x: getattr(self, x) for x in dir(all_props)
if (x.startswith("export_") or x == "use_selection") and all_props.get(x) is not None}
export_props = {
x: getattr(self, x) for x in dir(all_props)
if (x.startswith("export_") or x in exceptional) and all_props.get(x) is not None
}
context.scene[self.scene_key] = export_props
@ -479,6 +503,8 @@ class ExportGLTF2_Base:
export_settings['gltf_texcoords'] = self.export_texcoords
export_settings['gltf_normals'] = self.export_normals
export_settings['gltf_tangents'] = self.export_tangents and self.export_normals
export_settings['gltf_loose_edges'] = self.use_mesh_edges
export_settings['gltf_loose_points'] = self.use_mesh_vertices
if self.is_draco_available:
export_settings['gltf_draco_mesh_compression'] = self.export_draco_mesh_compression_enable
@ -692,6 +718,11 @@ class GLTF_PT_export_geometry(bpy.types.Panel):
col.active = operator.export_normals
col.prop(operator, 'export_tangents')
layout.prop(operator, 'export_colors')
col = layout.column()
col.prop(operator, 'use_mesh_edges')
col.prop(operator, 'use_mesh_vertices')
layout.prop(operator, 'export_materials')
col = layout.column()
col.active = operator.export_materials == "EXPORT"
@ -881,7 +912,7 @@ class GLTF_PT_export_user_extensions(bpy.types.Panel):
sfile = context.space_data
operator = sfile.active_operator
return operator.bl_idname == "EXPORT_SCENE_OT_gltf" and operator.has_active_extenions
return operator.bl_idname == "EXPORT_SCENE_OT_gltf" and operator.has_active_extensions
def draw(self, context):
layout = self.layout

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -283,6 +283,90 @@ def extract_primitives(glTF, blender_mesh, library, blender_object, blender_vert
'material': material_idx,
})
if export_settings['gltf_loose_edges']:
# Find loose edges
loose_edges = [e for e in blender_mesh.edges if e.is_loose]
blender_idxs = [vi for e in loose_edges for vi in e.vertices]
if blender_idxs:
# Export one glTF vert per unique Blender vert in a loose edge
blender_idxs = np.array(blender_idxs, dtype=np.uint32)
blender_idxs, indices = np.unique(blender_idxs, return_inverse=True)
attributes = {}
attributes['POSITION'] = locs[blender_idxs]
for morph_i, vs in enumerate(morph_locs):
attributes['MORPH_POSITION_%d' % morph_i] = vs[blender_idxs]
if skin:
joints = [[] for _ in range(num_joint_sets)]
weights = [[] for _ in range(num_joint_sets)]
for vi in blender_idxs:
bones = vert_bones[vi]
for j in range(0, 4 * num_joint_sets):
if j < len(bones):
joint, weight = bones[j]
else:
joint, weight = 0, 0.0
joints[j//4].append(joint)
weights[j//4].append(weight)
for i, (js, ws) in enumerate(zip(joints, weights)):
attributes['JOINTS_%d' % i] = js
attributes['WEIGHTS_%d' % i] = ws
primitives.append({
'attributes': attributes,
'indices': indices,
'mode': 1, # LINES
'material': 0,
})
if export_settings['gltf_loose_points']:
# Find loose points
verts_in_edge = set(vi for e in blender_mesh.edges for vi in e.vertices)
blender_idxs = [
vi for vi, _ in enumerate(blender_mesh.vertices)
if vi not in verts_in_edge
]
if blender_idxs:
blender_idxs = np.array(blender_idxs, dtype=np.uint32)
attributes = {}
attributes['POSITION'] = locs[blender_idxs]
for morph_i, vs in enumerate(morph_locs):
attributes['MORPH_POSITION_%d' % morph_i] = vs[blender_idxs]
if skin:
joints = [[] for _ in range(num_joint_sets)]
weights = [[] for _ in range(num_joint_sets)]
for vi in blender_idxs:
bones = vert_bones[vi]
for j in range(0, 4 * num_joint_sets):
if j < len(bones):
joint, weight = bones[j]
else:
joint, weight = 0, 0.0
joints[j//4].append(joint)
weights[j//4].append(weight)
for i, (js, ws) in enumerate(zip(joints, weights)):
attributes['JOINTS_%d' % i] = js
attributes['WEIGHTS_%d' % i] = ws
primitives.append({
'attributes': attributes,
'mode': 0, # POINTS
'material': 0,
})
print_console('INFO', 'Primitives created: %d' % len(primitives))
return primitives

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -56,7 +56,10 @@ def gather_animation_sampler(channels: typing.Tuple[bpy.types.FCurve],
bake_channel,
driver_obj,
export_settings)
if blender_object.parent is not None:
matrix_parent_inverse = blender_object.matrix_parent_inverse.copy().freeze()
else:
matrix_parent_inverse = mathutils.Matrix.Identity(4).freeze()
sampler = gltf2_io.AnimationSampler(
extensions=__gather_extensions(channels, blender_object_if_armature, export_settings, bake_bone, bake_channel),
@ -64,7 +67,8 @@ def gather_animation_sampler(channels: typing.Tuple[bpy.types.FCurve],
input=__gather_input(channels, blender_object_if_armature, non_keyed_values,
bake_bone, bake_channel, bake_range_start, bake_range_end, action_name, driver_obj, export_settings),
interpolation=__gather_interpolation(channels, blender_object_if_armature, export_settings, bake_bone, bake_channel),
output=__gather_output(channels, blender_object.matrix_parent_inverse.copy().freeze(),
output=__gather_output(channels,
matrix_parent_inverse,
blender_object_if_armature,
non_keyed_values,
bake_bone,

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -54,7 +54,7 @@ def gather_primitives(
material_idx = internal_primitive['material']
material = None
if export_settings['gltf_materials'] == "EXPORT":
if export_settings['gltf_materials'] == "EXPORT" and material_idx is not None:
blender_material = None
if material_names:
i = material_idx if material_idx < len(material_names) else -1
@ -73,7 +73,7 @@ def gather_primitives(
extras=None,
indices=internal_primitive['indices'],
material=material,
mode=None,
mode=internal_primitive['mode'],
targets=internal_primitive['targets']
)
primitives.append(primitive)
@ -101,7 +101,8 @@ def __gather_cache_primitives(
primitive = {
"attributes": __gather_attributes(internal_primitive, blender_mesh, modifiers, export_settings),
"indices": __gather_indices(internal_primitive, blender_mesh, modifiers, export_settings),
"material": internal_primitive['material'],
"mode": internal_primitive.get('mode'),
"material": internal_primitive.get('material'),
"targets": __gather_targets(internal_primitive, blender_mesh, modifiers, export_settings)
}
primitives.append(primitive)
@ -109,7 +110,9 @@ def __gather_cache_primitives(
return primitives
def __gather_indices(blender_primitive, blender_mesh, modifiers, export_settings):
indices = blender_primitive['indices']
indices = blender_primitive.get('indices')
if indices is None:
return None
# NOTE: Values used by some graphics APIs as "primitive restart" values are disallowed.
# Specifically, the values 65535 (in UINT16) and 4294967295 (in UINT32) cannot be used as indices.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@ -85,6 +85,10 @@ def __encode_primitive(primitive, dll, export_settings):
attributes = primitive.attributes
indices = primitive.indices
# Only do TRIANGLES primitives
if primitive.mode not in [None, 4]:
return
if 'POSITION' not in attributes:
print_console('WARNING', 'Draco encoder: Primitive without positions encountered. Skipping.')
return

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -1,4 +1,4 @@
# Copyright 2018-2019 The glTF-Blender-IO authors.
# Copyright 2018-2021 The glTF-Blender-IO authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
bl_info = {
@ -29,7 +29,7 @@ bl_info = {
"author": "Nutti, Mifth, Jace Priester, kgeogeo, mem, imdjs"
"Keith (Wahooney) Boshoff, McBuff, MaxRobinot, "
"Alexander Milovsky, Dusan Stevanovic, MatthiasThDs",
"version": (6, 4, 0),
"version": (6, 5, 0),
"blender": (2, 80, 0),
"location": "See Add-ons Preferences",
"description": "UV Toolset. See Add-ons Preferences for details",

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
from collections import defaultdict
from pprint import pprint
@ -333,7 +333,7 @@ def get_uvimg_editor_board_size(area):
return (255.0, 255.0)
def calc_polygon_2d_area(points):
def calc_tris_2d_area(points):
area = 0.0
for i, p1 in enumerate(points):
p2 = points[(i + 1) % len(points)]
@ -345,7 +345,7 @@ def calc_polygon_2d_area(points):
return fabs(0.5 * area)
def calc_polygon_3d_area(points):
def calc_tris_3d_area(points):
area = 0.0
for i, p1 in enumerate(points):
p2 = points[(i + 1) % len(points)]
@ -395,6 +395,23 @@ def get_faces_list(bm, method, only_selected):
return faces_list
def measure_all_faces_mesh_area(bm):
if compat.check_version(2, 80, 0) >= 0:
triangle_loops = bm.calc_loop_triangles()
else:
triangle_loops = bm.calc_tessface()
areas = {face: 0.0 for face in bm.faces}
for loops in triangle_loops:
face = loops[0].face
area = areas[face]
area += calc_tris_3d_area([l.vert.co for l in loops])
areas[face] = area
return areas
def measure_mesh_area(obj, calc_method, only_selected):
bm = bmesh.from_edit_mesh(obj.data)
if check_version(2, 73, 0) >= 0:
@ -406,17 +423,18 @@ def measure_mesh_area(obj, calc_method, only_selected):
areas = []
for faces in faces_list:
areas.append(measure_mesh_area_from_faces(faces))
areas.append(measure_mesh_area_from_faces(bm, faces))
return areas
def measure_mesh_area_from_faces(faces):
def measure_mesh_area_from_faces(bm, faces):
face_areas = measure_all_faces_mesh_area(bm)
mesh_area = 0.0
for f in faces:
verts = [l.vert.co for l in f.loops]
f_mesh_area = calc_polygon_3d_area(verts)
mesh_area = mesh_area + f_mesh_area
if f in face_areas:
mesh_area += face_areas[f]
return mesh_area
@ -486,12 +504,34 @@ def find_images(obj, face=None, tex_layer=None):
return images
def measure_uv_area_from_faces(obj, faces, uv_layer, tex_layer,
def measure_all_faces_uv_area(bm, uv_layer):
if compat.check_version(2, 80, 0) >= 0:
triangle_loops = bm.calc_loop_triangles()
else:
triangle_loops = bm.calc_tessface()
areas = {face: 0.0 for face in bm.faces}
for loops in triangle_loops:
face = loops[0].face
area = areas[face]
area += calc_tris_2d_area([l[uv_layer].uv for l in loops])
areas[face] = area
return areas
def measure_uv_area_from_faces(obj, bm, faces, uv_layer, tex_layer,
tex_selection_method, tex_size):
face_areas = measure_all_faces_uv_area(bm, uv_layer)
uv_area = 0.0
for f in faces:
uvs = [l[uv_layer].uv for l in f.loops]
f_uv_area = calc_polygon_2d_area(uvs)
if f not in face_areas:
continue
f_uv_area = face_areas[f]
# user specified
if tex_selection_method == 'USER_SPECIFIED' and tex_size is not None:
@ -547,8 +587,8 @@ def measure_uv_area_from_faces(obj, faces, uv_layer, tex_layer,
return uv_area
def measure_uv_area(obj, calc_method, tex_selection_method, tex_size,
only_selected):
def measure_uv_area(obj, calc_method, tex_selection_method,
tex_size, only_selected):
bm = bmesh.from_edit_mesh(obj.data)
if check_version(2, 73, 0) >= 0:
bm.verts.ensure_lookup_table()
@ -565,7 +605,8 @@ def measure_uv_area(obj, calc_method, tex_selection_method, tex_size,
uv_areas = []
for faces in faces_list:
uv_area = measure_uv_area_from_faces(
obj, faces, uv_layer, tex_layer, tex_selection_method, tex_size)
obj, bm, faces, uv_layer, tex_layer,
tex_selection_method, tex_size)
if uv_area is None:
return None
uv_areas.append(uv_area)
@ -946,7 +987,8 @@ class RingBuffer:
# clip: reference polygon
# subject: tested polygon
def __do_weiler_atherton_cliping(clip_uvs, subject_uvs, mode):
def __do_weiler_atherton_cliping(clip_uvs, subject_uvs, mode,
same_polygon_threshold):
clip_uvs = RingBuffer(clip_uvs)
if __is_polygon_flipped(clip_uvs):
@ -961,7 +1003,7 @@ def __do_weiler_atherton_cliping(clip_uvs, subject_uvs, mode):
debug_print(subject_uvs)
# check if clip and subject is overlapped completely
if __is_polygon_same(clip_uvs, subject_uvs):
if __is_polygon_same(clip_uvs, subject_uvs, same_polygon_threshold):
polygons = [subject_uvs.as_list()]
debug_print("===== Polygons Overlapped Completely =====")
debug_print(polygons)
@ -1193,26 +1235,31 @@ def get_uv_editable_objects(context):
return objs
def get_overlapped_uv_info(bm_list, faces_list, uv_layer_list, mode):
def get_overlapped_uv_info(bm_list, faces_list, uv_layer_list,
mode, same_polygon_threshold=0.0000001):
# at first, check island overlapped
isl = []
for bm, uv_layer, faces in zip(bm_list, uv_layer_list, faces_list):
info = get_island_info_from_faces(bm, faces, uv_layer)
isl.extend([(i, uv_layer) for i in info])
isl.extend([(i, uv_layer, bm) for i in info])
overlapped_isl_pairs = []
overlapped_uv_layer_pairs = []
for i, (i1, uv_layer_1) in enumerate(isl):
for i2, uv_layer_2 in isl[i + 1:]:
overlapped_bm_paris = []
for i, (i1, uv_layer_1, bm_1) in enumerate(isl):
for i2, uv_layer_2, bm_2 in isl[i + 1:]:
if (i1["max"].x < i2["min"].x) or (i2["max"].x < i1["min"].x) or \
(i1["max"].y < i2["min"].y) or (i2["max"].y < i1["min"].y):
continue
overlapped_isl_pairs.append([i1, i2])
overlapped_uv_layer_pairs.append([uv_layer_1, uv_layer_2])
overlapped_bm_paris.append([bm_1, bm_2])
# next, check polygon overlapped
overlapped_uvs = []
for oip, uvlp in zip(overlapped_isl_pairs, overlapped_uv_layer_pairs):
for oip, uvlp, bmp in zip(overlapped_isl_pairs,
overlapped_uv_layer_pairs,
overlapped_bm_paris):
for clip in oip[0]["faces"]:
f_clip = clip["face"]
clip_uvs = [l[uvlp[0]].uv.copy() for l in f_clip.loops]
@ -1228,11 +1275,13 @@ def get_overlapped_uv_info(bm_list, faces_list, uv_layer_list, mode):
subject_uvs = [l[uvlp[1]].uv.copy() for l in f_subject.loops]
# slow operation, apply Weiler-Atherton cliping algorithm
result, polygons = __do_weiler_atherton_cliping(clip_uvs,
subject_uvs,
mode)
result, polygons = \
__do_weiler_atherton_cliping(clip_uvs, subject_uvs,
mode, same_polygon_threshold)
if result:
overlapped_uvs.append({"clip_face": f_clip,
overlapped_uvs.append({"clip_bmesh": bmp[0],
"subject_bmesh": bmp[1],
"clip_face": f_clip,
"subject_face": f_subject,
"clip_uv_layer": uvlp[0],
"subject_uv_layer": uvlp[1],
@ -1242,14 +1291,15 @@ def get_overlapped_uv_info(bm_list, faces_list, uv_layer_list, mode):
return overlapped_uvs
def get_flipped_uv_info(faces_list, uv_layer_list):
def get_flipped_uv_info(bm_list, faces_list, uv_layer_list):
flipped_uvs = []
for faces, uv_layer in zip(faces_list, uv_layer_list):
for bm, faces, uv_layer in zip(bm_list, faces_list, uv_layer_list):
for f in faces:
polygon = RingBuffer([l[uv_layer].uv.copy() for l in f.loops])
if __is_polygon_flipped(polygon):
uvs = [l[uv_layer].uv.copy() for l in f.loops]
flipped_uvs.append({"face": f,
flipped_uvs.append({"bmesh": bm,
"face": f,
"uv_layer": uv_layer,
"uvs": uvs,
"polygons": [polygon.as_list()]})
@ -1257,7 +1307,7 @@ def get_flipped_uv_info(faces_list, uv_layer_list):
return flipped_uvs
def __is_polygon_same(points1, points2):
def __is_polygon_same(points1, points2, threshold):
if len(points1) != len(points2):
return False
@ -1267,7 +1317,7 @@ def __is_polygon_same(points1, points2):
for p1 in pts1:
for p2 in pts2:
diff = p2 - p1
if diff.length < 0.0000001:
if diff.length < threshold:
pts2.remove(p2)
break
else:

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
if "bpy" in locals():
import importlib

View File

@ -159,6 +159,11 @@ def glEnd():
#shader = gpu.shader.from_builtin('2D_IMAGE')
vert_shader, frag_shader = _get_transparency_shader()
shader = gpu.types.GPUShader(vert_shader, frag_shader)
elif inst.get_dims() == 3:
if len(tex_coords) == 0:
shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR')
else:
raise NotImplemented("Texture is not supported in get_dims() == 3")
else:
raise NotImplemented("get_dims() != 2")
@ -223,6 +228,12 @@ def glVertex2f(x, y):
inst.set_dims(2)
def glVertex3f(x, y, z):
inst = InternalData.get_instance()
inst.add_vert([x, y, z])
inst.set_dims(3)
def glTexCoord2f(u, v):
inst = InternalData.get_instance()
inst.add_tex_coord([u, v])
@ -234,6 +245,7 @@ GL_INT = bgl.GL_INT
GL_SCISSOR_BOX = bgl.GL_SCISSOR_BOX
GL_TEXTURE_2D = bgl.GL_TEXTURE_2D
GL_TEXTURE0 = bgl.GL_TEXTURE0
GL_DEPTH_TEST = bgl.GL_DEPTH_TEST
GL_TEXTURE_MIN_FILTER = 0
GL_TEXTURE_MAG_FILTER = 0

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
if "bpy" in locals():
import importlib

View File

@ -20,8 +20,8 @@
__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import math
from math import atan2, tan, sin, cos

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import bpy
from mathutils import Vector

View File

@ -20,8 +20,8 @@
__author__ = "Dusan Stevanovic, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import math

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>, Jace Priester"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import bmesh
import bpy.utils

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import bmesh
import bpy

View File

@ -20,8 +20,8 @@
__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import math
from math import atan2, sin, cos

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import bpy
import bmesh

View File

@ -20,8 +20,8 @@
__author__ = "Keith (Wahooney) Boshoff, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import bpy
from bpy.props import (
@ -30,7 +30,7 @@ from bpy.props import (
BoolProperty,
)
import bmesh
from mathutils import Vector
from mathutils import Vector, Euler
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
@ -65,15 +65,15 @@ def _is_vector_similar(v1, v2, error):
return within_err_x and within_err_y and within_err_z
def _mirror_uvs(uv_layer, src, dst, axis, error):
def _mirror_uvs(uv_layer, src, dst, axis, error, transformed):
"""
Copy UV coordinates from one UV face to another
"""
for sl in src.loops:
suv = sl[uv_layer].uv.copy()
svco = sl.vert.co.copy()
svco = transformed[sl.vert].copy()
for dl in dst.loops:
dvco = dl.vert.co.copy()
dvco = transformed[dl.vert].copy()
if axis == 'X':
dvco.x = -dvco.x
elif axis == 'Y':
@ -85,13 +85,14 @@ def _mirror_uvs(uv_layer, src, dst, axis, error):
dl[uv_layer].uv = suv.copy()
def _get_face_center(face):
def _get_face_center(face, transformed):
"""
Get center coordinate of the face
"""
center = Vector((0.0, 0.0, 0.0))
for v in face.verts:
center = center + v.co
tv = transformed[v]
center = center + tv
return center / len(face.verts)
@ -117,11 +118,22 @@ class _Properties:
description="Mirror Axis",
default='X'
)
scene.muv_mirror_uv_origin = EnumProperty(
items=(
('WORLD', "World", "World"),
("GLOBAL", "Global", "Global"),
('LOCAL', "Local", "Local"),
),
name="Origin",
description="Origin of the mirror operation",
default='LOCAL'
)
@classmethod
def del_props(cls, scene):
del scene.muv_mirror_uv_enabled
del scene.muv_mirror_uv_axis
del scene.muv_mirror_uv_origin
@BlClassRegistry()
@ -154,6 +166,16 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
soft_min=0.0,
soft_max=1.0
)
origin = EnumProperty(
items=(
('WORLD', "World", "World"),
("GLOBAL", "Global", "Global"),
('LOCAL', "Local", "Local"),
),
name="Origin",
description="Origin of the mirror operation",
default='LOCAL'
)
@classmethod
def poll(cls, context):
@ -162,6 +184,51 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
return True
return _is_valid_context(context)
def _get_world_vertices(self, obj, bm):
# Get world orientation matrix.
world_orientation_mat = obj.matrix_world
# Move to local to world.
transformed = {}
for v in bm.verts:
transformed[v] = compat.matmul(world_orientation_mat, v.co)
return transformed
def _get_global_vertices(self, obj, bm):
# Get world rotation matrix.
eular = Euler(obj.rotation_euler)
rotation_mat = eular.to_matrix()
# Get center location of all verticies.
center_location = Vector((0.0, 0.0, 0.0))
for v in bm.verts:
center_location += v.co
center_location /= len(bm.verts)
# Move to local to global.
transformed = {}
for v in bm.verts:
transformed[v] = compat.matmul(rotation_mat, v.co)
transformed[v] -= center_location
return transformed
def _get_local_vertices(self, _, bm):
transformed = {}
# Get center location of all verticies.
center_location = Vector((0.0, 0.0, 0.0))
for v in bm.verts:
center_location += v.co
center_location /= len(bm.verts)
for v in bm.verts:
transformed[v] = v.co.copy()
transformed[v] -= center_location
return transformed
def execute(self, context):
objs = common.get_uv_editable_objects(context)
@ -180,6 +247,13 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
return {'CANCELLED'}
uv_layer = bm.loops.layers.uv.verify()
if self.origin == 'WORLD':
transformed_verts = self._get_world_vertices(obj, bm)
elif self.origin == 'GLOBAL':
transformed_verts = self._get_global_vertices(obj, bm)
elif self.origin == 'LOCAL':
transformed_verts = self._get_local_vertices(obj, bm)
faces = [f for f in bm.faces if f.select]
for f_dst in faces:
count = len(f_dst.verts)
@ -191,8 +265,8 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
continue
# test if the vertices x values are the same sign
dst = _get_face_center(f_dst)
src = _get_face_center(f_src)
dst = _get_face_center(f_dst, transformed_verts)
src = _get_face_center(f_src, transformed_verts)
if (dst.x > 0 and src.x > 0) or (dst.x < 0 and src.x < 0):
continue
@ -207,7 +281,7 @@ class MUV_OT_MirrorUV(bpy.types.Operator):
# do mirror UV
if _is_vector_similar(dst, src, error):
_mirror_uvs(uv_layer, f_src, f_dst,
self.axis, self.error)
self.axis, self.error, transformed_verts)
bmesh.update_edit_mesh(obj.data)

View File

@ -20,8 +20,8 @@
__author__ = "kgeogeo, mem, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import bpy
from bpy.props import BoolProperty

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
from math import fabs
@ -151,7 +151,7 @@ class _Properties:
name="Allowable Center Deviation",
description="Allowable center deviation to judge same UV island",
min=0.000001,
max=0.1,
max=10.0,
default=(0.001, 0.001),
size=2
)
@ -159,7 +159,7 @@ class _Properties:
name="Allowable Size Deviation",
description="Allowable sizse deviation to judge same UV island",
min=0.000001,
max=0.1,
max=10.0,
default=(0.001, 0.001),
size=2
)
@ -196,12 +196,13 @@ class MUV_OT_PackUV(bpy.types.Operator):
description="Margin used by default pack UV function",
min=0,
max=1,
default=0.001)
default=0.001
)
allowable_center_deviation = FloatVectorProperty(
name="Allowable Center Deviation",
description="Allowable center deviation to judge same UV island",
min=0.000001,
max=0.1,
max=10.0,
default=(0.001, 0.001),
size=2
)
@ -209,7 +210,7 @@ class MUV_OT_PackUV(bpy.types.Operator):
name="Allowable Size Deviation",
description="Allowable sizse deviation to judge same UV island",
min=0.000001,
max=0.1,
max=10.0,
default=(0.001, 0.001),
size=2
)

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import bpy
from bpy.props import StringProperty, EnumProperty, BoolProperty

View File

@ -20,16 +20,17 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import bpy
from bpy.props import BoolProperty
from bpy.props import BoolProperty, FloatProperty, EnumProperty
import bmesh
from .. import common
from ..utils.bl_class_registry import BlClassRegistry
from ..utils.property_class_registry import PropertyClassRegistry
from ..utils import compatibility as compat
def _is_valid_context(context):
@ -61,13 +62,38 @@ class _Properties:
description="Select UV is enabled",
default=False
)
scene.muv_select_uv_same_polygon_threshold = FloatProperty(
name="Same Polygon Threshold",
description="Threshold to distinguish same polygons",
default=0.000001,
min=0.000001,
max=0.01,
step=0.00001
)
scene.muv_select_uv_selection_method = EnumProperty(
name="Selection Method",
description="How to select faces which have overlapped UVs",
items=[
('EXTEND', "Extend",
"Select faces without unselecting selected faces"),
('RESET', "Reset", "Select faces and unselect selected faces"),
],
default='RESET'
)
scene.muv_select_uv_sync_mesh_selection = BoolProperty(
name="Sync Mesh Selection",
description="Select the mesh's faces as well as UV's faces",
default=False
)
@classmethod
def del_props(cls, scene):
del scene.muv_select_uv_enabled
del scene.muv_select_uv_same_polygon_threshold
@BlClassRegistry()
@compat.make_annotations
class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
"""
Operation class: Select faces which have overlapped UVs
@ -78,6 +104,30 @@ class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
bl_description = "Select faces which have overlapped UVs"
bl_options = {'REGISTER', 'UNDO'}
same_polygon_threshold = FloatProperty(
name="Same Polygon Threshold",
description="Threshold to distinguish same polygons",
default=0.000001,
min=0.000001,
max=0.01,
step=0.00001
)
selection_method = EnumProperty(
name="Selection Method",
description="How to select faces which have overlapped UVs",
items=[
('EXTEND', "Extend",
"Select faces without unselecting selected faces"),
('RESET', "Reset", "Select faces and unselect selected faces"),
],
default='RESET'
)
sync_mesh_selection = BoolProperty(
name="Sync Mesh Selection",
description="Select mesh's faces as well as UV's faces",
default=False
)
@classmethod
def poll(cls, context):
# we can not get area/space/region from console
@ -85,6 +135,12 @@ class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
return True
return _is_valid_context(context)
@staticmethod
def setup_argument(ops, scene):
ops.same_polygon_threshold = scene.muv_select_uv_same_polygon_threshold
ops.selection_method = scene.muv_select_uv_selection_method
ops.sync_mesh_selection = scene.muv_select_uv_sync_mesh_selection
def execute(self, context):
objs = common.get_uv_editable_objects(context)
@ -105,13 +161,29 @@ class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
uv_layer_list.append(uv_layer)
faces_list.append(sel_faces)
overlapped_info = common.get_overlapped_uv_info(bm_list, faces_list,
uv_layer_list, 'FACE')
overlapped_info = common.get_overlapped_uv_info(
bm_list, faces_list, uv_layer_list, 'FACE',
self.same_polygon_threshold)
if self.selection_method == 'RESET':
if context.tool_settings.use_uv_select_sync:
for faces in faces_list:
for f in faces:
f.select = False
else:
for uv_layer, faces in zip(uv_layer_list, faces_list):
for f in faces:
if self.sync_mesh_selection:
f.select = False
for l in f.loops:
l[uv_layer].select = False
for info in overlapped_info:
if context.tool_settings.use_uv_select_sync:
info["subject_face"].select = True
else:
if self.sync_mesh_selection:
info["subject_face"].select = True
for l in info["subject_face"].loops:
l[info["subject_uv_layer"]].select = True
@ -122,6 +194,7 @@ class MUV_OT_SelectUV_SelectOverlapped(bpy.types.Operator):
@BlClassRegistry()
@compat.make_annotations
class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
"""
Operation class: Select faces which have flipped UVs
@ -132,6 +205,22 @@ class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
bl_description = "Select faces which have flipped UVs"
bl_options = {'REGISTER', 'UNDO'}
selection_method = EnumProperty(
name="Selection Method",
description="How to select faces which have overlapped UVs",
items=[
('EXTEND', "Extend",
"Select faces without unselecting selected faces"),
('RESET', "Reset", "Select faces and unselect selected faces"),
],
default='RESET'
)
sync_mesh_selection = BoolProperty(
name="Sync Mesh Selection",
description="Select mesh's faces as well as UV's faces",
default=False
)
@classmethod
def poll(cls, context):
# we can not get area/space/region from console
@ -139,6 +228,11 @@ class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
return True
return _is_valid_context(context)
@staticmethod
def setup_argument(ops, scene):
ops.selection_method = scene.muv_select_uv_selection_method
ops.sync_mesh_selection = scene.muv_select_uv_sync_mesh_selection
def execute(self, context):
objs = common.get_uv_editable_objects(context)
@ -159,12 +253,28 @@ class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
uv_layer_list.append(uv_layer)
faces_list.append(sel_faces)
flipped_info = common.get_flipped_uv_info(faces_list, uv_layer_list)
flipped_info = common.get_flipped_uv_info(
bm_list, faces_list, uv_layer_list)
if self.selection_method == 'RESET':
if context.tool_settings.use_uv_select_sync:
for faces in faces_list:
for f in faces:
f.select = False
else:
for uv_layer, faces in zip(uv_layer_list, faces_list):
for f in faces:
if self.sync_mesh_selection:
f.select = False
for l in f.loops:
l[uv_layer].select = False
for info in flipped_info:
if context.tool_settings.use_uv_select_sync:
info["face"].select = True
else:
if self.sync_mesh_selection:
info["face"].select = True
for l in info["face"].loops:
l[info["uv_layer"]].select = True
@ -172,3 +282,84 @@ class MUV_OT_SelectUV_SelectFlipped(bpy.types.Operator):
bmesh.update_edit_mesh(obj.data)
return {'FINISHED'}
@BlClassRegistry()
class MUV_OT_SelectUV_ZoomSelectedUV(bpy.types.Operator):
"""
Operation class: Zoom selected UV in View3D space
"""
bl_idname = "uv.muv_select_uv_zoom_selected_uv"
bl_label = "Zoom Selected UV"
bl_description = "Zoom selected UV in View3D space"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
# we can not get area/space/region from console
if common.is_console_mode():
return True
return _is_valid_context(context)
def _get_override_context(self, context):
for window in context.window_manager.windows:
screen = window.screen
for area in screen.areas:
if area.type == 'VIEW_3D':
for region in area.regions:
if region.type == 'WINDOW':
return {'window': window, 'screen': screen,
'area': area, 'region': region}
return None
def execute(self, context):
objs = common.get_uv_editable_objects(context)
bm_list = []
uv_layer_list = []
verts_list = []
for obj in objs:
bm = bmesh.from_edit_mesh(obj.data)
if common.check_version(2, 73, 0) >= 0:
bm.verts.ensure_lookup_table()
uv_layer = bm.loops.layers.uv.verify()
sel_verts = [v for v in bm.verts if v.select]
bm_list.append(bm)
uv_layer_list.append(uv_layer)
verts_list.append(sel_verts)
# Get all selected UV vertices in UV Editor.
sel_uv_verts = []
for vlist, uv_layer in zip(verts_list, uv_layer_list):
for v in vlist:
for l in v.link_loops:
if l[uv_layer].select or \
context.tool_settings.use_uv_select_sync:
sel_uv_verts.append(v)
break
# Select vertices only selected in UV Editor.
for bm in bm_list:
for v in bm.verts:
v.select = False
for v in sel_uv_verts:
v.select = True
for obj in objs:
bmesh.update_edit_mesh(obj.data)
# Zoom.
override_context = self._get_override_context(context)
if override_context is None:
self.report({'WARNING'}, "More than one 'VIEW_3D' area must exist")
return {'CANCELLED'}
bpy.ops.view3d.view_selected(override_context, use_all_regions=False)
# Revert selection of verticies.
for v in sel_verts:
v.select = True
for obj in objs:
bmesh.update_edit_mesh(obj.data)
return {'FINISHED'}

View File

@ -20,8 +20,8 @@
__author__ = "imdjs, Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import bpy
from bpy.props import BoolProperty, FloatProperty

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import math
from math import atan2, cos, sqrt, sin, fabs

View File

@ -20,10 +20,11 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
from collections import namedtuple
from math import sin, cos
import bpy
import bmesh
@ -32,6 +33,7 @@ from bpy.props import (
BoolProperty,
EnumProperty,
FloatProperty,
FloatVectorProperty,
)
import mathutils
@ -56,7 +58,7 @@ def _get_loaded_texture_name(_, __):
return items
def _get_canvas(context, magnitude):
def _get_canvas(context):
"""
Get canvas to be renderred texture
"""
@ -88,11 +90,11 @@ def _get_canvas(context, magnitude):
len_y = canvas_h
else:
if sc.muv_texture_projection_apply_tex_aspect:
len_x = tex_w * magnitude
len_y = tex_h * magnitude
len_x = tex_w
len_y = tex_h
else:
len_x = region_w * magnitude
len_y = region_h * magnitude
len_x = region_w
len_y = region_h
x0 = int(center_x - len_x * 0.5)
y0 = int(center_y - len_y * 0.5)
@ -123,6 +125,35 @@ def _region_to_canvas(rg_vec, canvas):
return cv_vec
def _create_affine_matrix(identity, scale, rotate, translate):
if identity:
return mathutils.Matrix.Identity(3)
sx = scale[0]
sy = scale[1]
theta = rotate
tx = translate[0]
ty = translate[1]
mat_scale = mathutils.Matrix((
(sx, 0.0, 0.0),
(0.0, sy, 0.0),
(0.0, 0.0, 1.0)
))
mat_rotate = mathutils.Matrix((
(cos(theta), sin(theta), 0.0),
(-sin(theta), cos(theta), 0.0),
(0.0, 0.0, 1.0)
))
mat_translate = mathutils.Matrix((
(1.0, 0.0, tx),
(0.0, 1.0, ty),
(0.0, 0.0, 1.0)
))
return compat.matmul(compat.matmul(mat_translate, mat_rotate), mat_scale)
def _is_valid_context(context):
objs = common.get_uv_editable_objects(context)
if not objs:
@ -167,12 +198,31 @@ class _Properties:
set=set_func,
update=update_func
)
scene.muv_texture_projection_tex_magnitude = FloatProperty(
name="Magnitude",
description="Texture Magnitude",
default=0.5,
min=0.0,
max=100.0
scene.muv_texture_projection_tex_scaling = FloatVectorProperty(
name="Scaling",
description="Texture Scale",
default=(0.5, 0.5),
min=-100.0,
max=100.0,
size=2,
subtype='XYZ'
)
scene.muv_texture_projection_tex_rotation = FloatProperty(
name="Rotation",
description="Texture Rotate",
default=0.0,
min=-360.0,
max=360.0,
subtype='ANGLE'
)
scene.muv_texture_projection_tex_translation = FloatVectorProperty(
name="Translation",
description="Texture Translate",
default=(0.0, 0.0),
min=-2000.0,
max=2000.0,
size=2,
subtype='XYZ'
)
scene.muv_texture_projection_tex_image = EnumProperty(
name="Image",
@ -188,7 +238,7 @@ class _Properties:
)
scene.muv_texture_projection_adjust_window = BoolProperty(
name="Adjust Window",
description="Size of renderered texture is fitted to window",
description="Scale of renderered texture is fitted to window",
default=True
)
scene.muv_texture_projection_apply_tex_aspect = BoolProperty(
@ -205,7 +255,9 @@ class _Properties:
@classmethod
def del_props(cls, scene):
del scene.muv_texture_projection_enabled
del scene.muv_texture_projection_tex_magnitude
del scene.muv_texture_projection_tex_scaling
del scene.muv_texture_projection_tex_rotation
del scene.muv_texture_projection_tex_translation
del scene.muv_texture_projection_tex_image
del scene.muv_texture_projection_tex_transparency
del scene.muv_texture_projection_adjust_window
@ -264,12 +316,33 @@ class MUV_OT_TextureProjection(bpy.types.Operator):
img = bpy.data.images[sc.muv_texture_projection_tex_image]
# setup rendering region
rect = _get_canvas(context, sc.muv_texture_projection_tex_magnitude)
rect = _get_canvas(context)
# Apply affine transformation.
center = mathutils.Vector((
(rect.x1 + rect.x0) / 2.0,
(rect.y1 + rect.y0) / 2.0,
0.0,
))
p1 = mathutils.Vector((rect.x0 - center.x, rect.y0 - center.y, 1.0))
p2 = mathutils.Vector((rect.x0 - center.x, rect.y1 - center.y, 1.0))
p3 = mathutils.Vector((rect.x1 - center.x, rect.y1 - center.y, 1.0))
p4 = mathutils.Vector((rect.x1 - center.x, rect.y0 - center.y, 1.0))
mat_affine = _create_affine_matrix(
sc.muv_texture_projection_adjust_window,
sc.muv_texture_projection_tex_scaling,
sc.muv_texture_projection_tex_rotation,
sc.muv_texture_projection_tex_translation)
p1 = compat.matmul(mat_affine, p1) + center
p2 = compat.matmul(mat_affine, p2) + center
p3 = compat.matmul(mat_affine, p3) + center
p4 = compat.matmul(mat_affine, p4) + center
positions = [
[rect.x0, rect.y0],
[rect.x0, rect.y1],
[rect.x1, rect.y1],
[rect.x1, rect.y0]
[p1.x, p1.y],
[p2.x, p2.y],
[p3.x, p3.y],
[p4.x, p4.y]
]
tex_coords = [
[0.0, 0.0],
@ -384,13 +457,30 @@ class MUV_OT_TextureProjection_Project(bpy.types.Operator):
for f in sel_faces for l in f.loops
]
# Apply affine transformation.
rect = _get_canvas(bpy.context)
center = mathutils.Vector((
(rect.x1 + rect.x0) / 2.0,
(rect.y1 + rect.y0) / 2.0,
0.0,
))
v_screen_transformed = []
for v in v_screen:
p1 = mathutils.Vector((v.x - center.x, v.y - center.y, 1.0))
mat_affine = _create_affine_matrix(
sc.muv_texture_projection_adjust_window,
sc.muv_texture_projection_tex_scaling,
sc.muv_texture_projection_tex_rotation,
sc.muv_texture_projection_tex_translation)
p1 = compat.matmul(mat_affine.inverted(), p1) + center
v_screen_transformed.append(p1)
# transform screen region to canvas
v_canvas = [
_region_to_canvas(
v,
_get_canvas(bpy.context,
sc.muv_texture_projection_tex_magnitude)
) for v in v_screen
rect
) for v in v_screen_transformed
]
# assign image

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import bpy
from bpy.props import (

View File

@ -20,8 +20,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>, Mifth, MaxRobinot"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
from collections import OrderedDict

View File

@ -18,8 +18,8 @@
__author__ = "Nutti <nutti.metro@gmail.com>"
__status__ = "production"
__version__ = "6.4"
__date__ = "23 Oct 2020"
__version__ = "6.5"
__date__ = "6 Mar 2021"
import bpy
from bpy.props import (

Some files were not shown because too many files have changed in this diff Show More