Fix material move (fill opacity problem comes from blender 4.3 itself)
parent
4d6dc06e4e
commit
58e6816e39
|
@ -373,11 +373,7 @@ def add_multiple_strokes(stroke_list, layer=None, use_current_frame=True, select
|
||||||
|
|
||||||
for s in stroke_list:
|
for s in stroke_list:
|
||||||
add_stroke(s, target_frame, layer, obj, select=select)
|
add_stroke(s, target_frame, layer, obj, select=select)
|
||||||
'''
|
|
||||||
for s in stroke_data:
|
|
||||||
add_stroke(s, target_frame)
|
|
||||||
'''
|
|
||||||
|
|
||||||
# print(len(stroke_list), 'strokes pasted')
|
# print(len(stroke_list), 'strokes pasted')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import numpy as np
|
||||||
from time import time
|
from time import time
|
||||||
from .utils import (location_to_region, region_to_location)
|
from .utils import (location_to_region, region_to_location)
|
||||||
|
|
||||||
|
## DISABLED (in init, also in menu append, see register below)
|
||||||
"""
|
"""
|
||||||
## Do not work on multiple object
|
## Do not work on multiple object
|
||||||
def batch_flat_reproject(obj, proj_type='VIEW', all_strokes=True, restore_frame=False):
|
def batch_flat_reproject(obj, proj_type='VIEW', all_strokes=True, restore_frame=False):
|
||||||
|
|
|
@ -93,6 +93,7 @@ class GPTB_OT_move_material_to_layer(Operator) :
|
||||||
# t = time.time() # Dbg
|
# t = time.time() # Dbg
|
||||||
total = 0
|
total = 0
|
||||||
oct = 0
|
oct = 0
|
||||||
|
|
||||||
for ob in pool:
|
for ob in pool:
|
||||||
mat_index = next((i for i, ms in enumerate(ob.material_slots) if ms.material and ms.material == mat), None)
|
mat_index = next((i for i, ms in enumerate(ob.material_slots) if ms.material and ms.material == mat), None)
|
||||||
if mat_index is None:
|
if mat_index is None:
|
||||||
|
@ -110,26 +111,26 @@ class GPTB_OT_move_material_to_layer(Operator) :
|
||||||
### Move Strokes to a new key (or existing key if comming for yet another layer)
|
### Move Strokes to a new key (or existing key if comming for yet another layer)
|
||||||
fct = 0
|
fct = 0
|
||||||
sct = 0
|
sct = 0
|
||||||
for l in gpl:
|
for layer in gpl:
|
||||||
if l == target_layer:
|
if layer == target_layer:
|
||||||
## ! infinite loop if target layer is included
|
## ! infinite loop if target layer is included
|
||||||
continue
|
continue
|
||||||
for f in l.frames:
|
for fr in layer.frames:
|
||||||
## skip if no stroke has active material
|
## skip if no stroke has active material
|
||||||
if not next((s for s in f.drawing.strokes if s.material_index == mat_index), None):
|
if not next((s for s in fr.drawing.strokes if s.material_index == mat_index), None):
|
||||||
continue
|
continue
|
||||||
## Get/Create a destination frame and keep a reference to it
|
## Get/Create a destination frame and keep a reference to it
|
||||||
if not (dest_key := key_dict.get(f.frame_number)):
|
if not (dest_key := key_dict.get(fr.frame_number)):
|
||||||
dest_key = target_layer.frames.new(f.frame_number)
|
dest_key = target_layer.frames.new(fr.frame_number)
|
||||||
key_dict[dest_key.frame_number] = dest_key
|
key_dict[dest_key.frame_number] = dest_key
|
||||||
|
|
||||||
print(f'{ob.name} : frame {f.frame_number}')
|
print(f'{ob.name} : frame {fr.frame_number}')
|
||||||
## Replicate strokes in dest_keys
|
## Replicate strokes in dest_keys
|
||||||
stroke_to_delete = []
|
stroke_to_delete = []
|
||||||
for s in f.drawing.strokes:
|
for s_idx, s in enumerate(fr.drawing.strokes):
|
||||||
if s.material_index == mat_index:
|
if s.material_index == mat_index:
|
||||||
utils.copy_stroke_to_frame(s, dest_key)
|
utils.copy_stroke_to_frame(s, dest_key)
|
||||||
stroke_to_delete.append(s)
|
stroke_to_delete.append(s_idx)
|
||||||
|
|
||||||
## Debug
|
## Debug
|
||||||
# if time.time() - t > 10:
|
# if time.time() - t > 10:
|
||||||
|
@ -138,17 +139,16 @@ class GPTB_OT_move_material_to_layer(Operator) :
|
||||||
|
|
||||||
sct += len(stroke_to_delete)
|
sct += len(stroke_to_delete)
|
||||||
|
|
||||||
# print('Removing frames') # Dbg
|
## Remove from source frame (fr)
|
||||||
## Remove from source frame (f)
|
|
||||||
if not self.copy:
|
if not self.copy:
|
||||||
for s in reversed(stroke_to_delete):
|
# print('Removing frames') # Dbg
|
||||||
f.drawing.strokes.remove(s)
|
if stroke_to_delete:
|
||||||
|
fr.drawing.remove_strokes(indices=stroke_to_delete)
|
||||||
|
|
||||||
## ? Remove frame if layer is empty ? -> probably not, will show previous frame
|
## ? Remove frame if layer is empty ? -> probably not, otherwise will show previous frame
|
||||||
|
|
||||||
fct += 1
|
fct += 1
|
||||||
l.frames.update()
|
|
||||||
|
|
||||||
|
|
||||||
if fct:
|
if fct:
|
||||||
oct += 1
|
oct += 1
|
||||||
|
|
|
@ -4,7 +4,7 @@ bl_info = {
|
||||||
"name": "GP toolbox",
|
"name": "GP toolbox",
|
||||||
"description": "Tool set for Grease Pencil in animation production",
|
"description": "Tool set for Grease Pencil in animation production",
|
||||||
"author": "Samuel Bernou, Christophe Seux",
|
"author": "Samuel Bernou, Christophe Seux",
|
||||||
"version": (4, 0, 1),
|
"version": (4, 0, 2),
|
||||||
"blender": (4, 3, 0),
|
"blender": (4, 3, 0),
|
||||||
"location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties",
|
"location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties",
|
||||||
"warning": "",
|
"warning": "",
|
||||||
|
@ -35,7 +35,7 @@ from . import OP_brushes
|
||||||
from . import OP_file_checker
|
from . import OP_file_checker
|
||||||
from . import OP_copy_paste
|
from . import OP_copy_paste
|
||||||
from . import OP_realign
|
from . import OP_realign
|
||||||
from . import OP_flat_reproject
|
# from . import OP_flat_reproject # Disabled
|
||||||
from . import OP_depth_move
|
from . import OP_depth_move
|
||||||
from . import OP_key_duplicate_send
|
from . import OP_key_duplicate_send
|
||||||
from . import OP_layer_manager
|
from . import OP_layer_manager
|
||||||
|
@ -793,7 +793,7 @@ addon_modules = (
|
||||||
OP_brushes,
|
OP_brushes,
|
||||||
OP_cursor_snap_canvas,
|
OP_cursor_snap_canvas,
|
||||||
OP_copy_paste,
|
OP_copy_paste,
|
||||||
OP_flat_reproject,
|
# OP_flat_reproject # Disabled,
|
||||||
OP_realign,
|
OP_realign,
|
||||||
OP_depth_move,
|
OP_depth_move,
|
||||||
OP_key_duplicate_send,
|
OP_key_duplicate_send,
|
||||||
|
|
194
utils.py
194
utils.py
|
@ -10,14 +10,80 @@ from math import sqrt
|
||||||
from mathutils import Vector
|
from mathutils import Vector
|
||||||
from sys import platform
|
from sys import platform
|
||||||
|
|
||||||
|
## constants values
|
||||||
|
|
||||||
|
|
||||||
""" def get_gp_parent(layer) :
|
## Default stroke and points attributes
|
||||||
if layer.parent_type == "BONE" and layer.parent_bone :
|
stroke_attr = [
|
||||||
return layer.parent.pose.bones.get(layer.parent_bone)
|
'start_cap',
|
||||||
else :
|
'end_cap',
|
||||||
return layer.parent
|
'softness',
|
||||||
"""
|
'material_index',
|
||||||
|
'fill_opacity',
|
||||||
|
'fill_color',
|
||||||
|
'cyclic',
|
||||||
|
'aspect_ratio',
|
||||||
|
'time_start',
|
||||||
|
# 'curve_type', # read-only
|
||||||
|
]
|
||||||
|
|
||||||
|
point_attr = [
|
||||||
|
'position',
|
||||||
|
'radius',
|
||||||
|
'rotation',
|
||||||
|
'opacity',
|
||||||
|
'vertex_color',
|
||||||
|
'delta_time',
|
||||||
|
# 'select',
|
||||||
|
]
|
||||||
|
|
||||||
|
### Attribute value, types and shape
|
||||||
|
|
||||||
|
attribute_value_string = {
|
||||||
|
'FLOAT': "value",
|
||||||
|
'INT': "value",
|
||||||
|
'FLOAT_VECTOR': "vector",
|
||||||
|
'FLOAT_COLOR': "color",
|
||||||
|
'BYTE_COLOR': "color",
|
||||||
|
'STRING': "value",
|
||||||
|
'BOOLEAN': "value",
|
||||||
|
'FLOAT2': "value",
|
||||||
|
'INT8': "value",
|
||||||
|
'INT32_2D': "value",
|
||||||
|
'QUATERNION': "value",
|
||||||
|
'FLOAT4X4': "value",
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute_value_dtype = {
|
||||||
|
'FLOAT': np.float32,
|
||||||
|
'INT': np.dtype('int'),
|
||||||
|
'FLOAT_VECTOR': np.float32,
|
||||||
|
'FLOAT_COLOR': np.float32,
|
||||||
|
'BYTE_COLOR': np.int8,
|
||||||
|
'STRING': np.dtype('str'),
|
||||||
|
'BOOLEAN': np.dtype('bool'),
|
||||||
|
'FLOAT2': np.float32,
|
||||||
|
'INT8': np.int8,
|
||||||
|
'INT32_2D': np.dtype('int'),
|
||||||
|
'QUATERNION': np.float32,
|
||||||
|
'FLOAT4X4': np.float32,
|
||||||
|
}
|
||||||
|
|
||||||
|
attribute_value_shape = {
|
||||||
|
'FLOAT': (),
|
||||||
|
'INT': (),
|
||||||
|
'FLOAT_VECTOR': (3,),
|
||||||
|
'FLOAT_COLOR': (4,),
|
||||||
|
'BYTE_COLOR': (4,),
|
||||||
|
'STRING': (),
|
||||||
|
'BOOLEAN': (),
|
||||||
|
'FLOAT2':(2,),
|
||||||
|
'INT8': (),
|
||||||
|
'INT32_2D': (2,),
|
||||||
|
'QUATERNION': (4,),
|
||||||
|
'FLOAT4X4': (4,4),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def translate_range(OldValue, OldMin, OldMax, NewMax, NewMin):
|
def translate_range(OldValue, OldMin, OldMax, NewMax, NewMin):
|
||||||
return (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
|
return (((OldValue - OldMin) * (NewMax - NewMin)) / (OldMax - OldMin)) + NewMin
|
||||||
|
@ -557,64 +623,30 @@ def copy_stroke_to_frame(s, frame, select=True):
|
||||||
return created stroke
|
return created stroke
|
||||||
'''
|
'''
|
||||||
|
|
||||||
ns = frame.drawing.strokes.new()
|
frame.drawing.add_strokes([len(s.points)])
|
||||||
|
ns = frame.drawing.strokes[-1]
|
||||||
## Set strokes attr
|
# print(len(s.points), 'new:', len(ns.points))
|
||||||
stroke_attr = [
|
#ns.material_index
|
||||||
'line_width',
|
|
||||||
'material_index',
|
|
||||||
'draw_cyclic',
|
|
||||||
'use_cyclic',
|
|
||||||
'uv_scale',
|
|
||||||
'uv_rotation',
|
|
||||||
'hardness',
|
|
||||||
'uv_translation',
|
|
||||||
'vertex_color_fill',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
## replicate attributes (simple loop)
|
||||||
|
## TODO : might need to create atribute domain if does not exists in destination
|
||||||
for attr in stroke_attr:
|
for attr in stroke_attr:
|
||||||
if not hasattr(s, attr):
|
|
||||||
continue
|
|
||||||
# print(f'transfer stroke {attr}') # Dbg
|
|
||||||
setattr(ns, attr, getattr(s, attr))
|
setattr(ns, attr, getattr(s, attr))
|
||||||
|
|
||||||
## create points
|
for src_p, dest_p in zip(s.points, ns.points):
|
||||||
point_count = len(s.points)
|
for attr in point_attr:
|
||||||
ns.points.add(len(s.points))
|
setattr(dest_p, attr, getattr(src_p, attr))
|
||||||
|
## Define selection
|
||||||
## Set points attr
|
dest_p.select=select
|
||||||
# for p, np in zip(s.points, ns.points):
|
|
||||||
flat_list = [0.0] * point_count
|
|
||||||
flat_uv_fill_list = [0.0, 0.0] * point_count
|
|
||||||
flat_vector_list = [0.0, 0.0, 0.0] * point_count
|
|
||||||
flat_color_list = [0.0, 0.0, 0.0, 0.0] * point_count
|
|
||||||
|
|
||||||
single_attr = [
|
|
||||||
'pressure',
|
|
||||||
'strength',
|
|
||||||
'uv_factor',
|
|
||||||
'uv_rotation',
|
|
||||||
]
|
|
||||||
|
|
||||||
for attr in single_attr:
|
## Direcly iterate over attribute ?
|
||||||
# print(f'transfer point {attr}') # Dbg
|
# src_start = src_dr.curve_offsets[0].value
|
||||||
s.points.foreach_get(attr, flat_list)
|
# src_end = src_start + data_size
|
||||||
ns.points.foreach_set(attr, flat_list)
|
# dst_start = dst_dr.curve_offsets[0].value
|
||||||
|
# dst_end = dst_start + data_size
|
||||||
|
# for src_idx, dest_idx in zip(range(src_start, src_end),range(dst_start, dst_end)):
|
||||||
|
# setattr(dest_attr.data[dest_idx], val_type, getattr(source_attr.data[src_idx], val_type))
|
||||||
|
|
||||||
# print(f'transfer point co') # Dbg
|
|
||||||
s.points.foreach_get('co', flat_vector_list)
|
|
||||||
ns.points.foreach_set('co', flat_vector_list)
|
|
||||||
|
|
||||||
# print(f'transfer point uv_fill') # Dbg
|
|
||||||
s.points.foreach_get('uv_fill', flat_uv_fill_list)
|
|
||||||
ns.points.foreach_set('uv_fill', flat_uv_fill_list)
|
|
||||||
|
|
||||||
# print(f'transfer point vertex_color') # Dbg
|
|
||||||
s.points.foreach_get('vertex_color', flat_color_list)
|
|
||||||
ns.points.foreach_set('vertex_color', flat_color_list)
|
|
||||||
|
|
||||||
ns.select = select
|
|
||||||
ns.points.update()
|
|
||||||
return ns
|
return ns
|
||||||
|
|
||||||
"""## Works, but do not copy all attributes type (probably ok for GP though)
|
"""## Works, but do not copy all attributes type (probably ok for GP though)
|
||||||
|
@ -657,52 +689,6 @@ def bulk_frame_copy_attributes(source_attr, target_attr):
|
||||||
# setattr(dest_attr.data[dest_idx], val_type, getattr(source_attr.data[src_idx], val_type))
|
# setattr(dest_attr.data[dest_idx], val_type, getattr(source_attr.data[src_idx], val_type))
|
||||||
"""
|
"""
|
||||||
|
|
||||||
attribute_value_string = {
|
|
||||||
'FLOAT': "value",
|
|
||||||
'INT': "value",
|
|
||||||
'FLOAT_VECTOR': "vector",
|
|
||||||
'FLOAT_COLOR': "color",
|
|
||||||
'BYTE_COLOR': "color",
|
|
||||||
'STRING': "value",
|
|
||||||
'BOOLEAN': "value",
|
|
||||||
'FLOAT2': "value",
|
|
||||||
'INT8': "value",
|
|
||||||
'INT32_2D': "value",
|
|
||||||
'QUATERNION': "value",
|
|
||||||
'FLOAT4X4': "value",
|
|
||||||
}
|
|
||||||
|
|
||||||
attribute_value_dtype = {
|
|
||||||
'FLOAT': np.float32,
|
|
||||||
'INT': np.dtype('int'),
|
|
||||||
'FLOAT_VECTOR': np.float32,
|
|
||||||
'FLOAT_COLOR': np.float32,
|
|
||||||
'BYTE_COLOR': np.int8,
|
|
||||||
'STRING': np.dtype('str'),
|
|
||||||
'BOOLEAN': np.dtype('bool'),
|
|
||||||
'FLOAT2': np.float32,
|
|
||||||
'INT8': np.int8,
|
|
||||||
'INT32_2D': np.dtype('int'),
|
|
||||||
'QUATERNION': np.float32,
|
|
||||||
'FLOAT4X4': np.float32,
|
|
||||||
}
|
|
||||||
|
|
||||||
attribute_value_shape = {
|
|
||||||
'FLOAT': (),
|
|
||||||
'INT': (),
|
|
||||||
'FLOAT_VECTOR': (3,),
|
|
||||||
'FLOAT_COLOR': (4,),
|
|
||||||
'BYTE_COLOR': (4,),
|
|
||||||
'STRING': (),
|
|
||||||
'BOOLEAN': (),
|
|
||||||
'FLOAT2':(2,),
|
|
||||||
'INT8': (),
|
|
||||||
'INT32_2D': (2,),
|
|
||||||
'QUATERNION': (4,),
|
|
||||||
'FLOAT4X4': (4,4),
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def bulk_copy_attributes(source_attr, target_attr):
|
def bulk_copy_attributes(source_attr, target_attr):
|
||||||
'''Get and apply data as flat numpy array based on attribute type'''
|
'''Get and apply data as flat numpy array based on attribute type'''
|
||||||
value_string = attribute_value_string[source_attr.data_type]
|
value_string = attribute_value_string[source_attr.data_type]
|
||||||
|
|
Loading…
Reference in New Issue