Public release
0.9.1: - Public release - prefs: added fps as part of project settings - check file use pref fps value (previously used harcoded 24fps value) - cleanup: Remove wip GMIC-bridge tools that need to be done separately (if needed) - update: apply changes in integrated copy-paste from the last version of standalone addon - doc: Added fully-detailed french readmegpv2
parent
98c6739003
commit
f642d943ff
|
@ -1,34 +1,24 @@
|
|||
## Can be renamed and used as standalone __init__.py file
|
||||
bl_info = {
|
||||
"name": "GP guided colorize",
|
||||
"description": "Blender <> G'MIC bridge for auto color",
|
||||
"author": "Samuel Bernou",
|
||||
"version": (0, 1, 0),
|
||||
"blender": (2, 82, 0),
|
||||
"location": "3D view > Gpencil > Colorize",
|
||||
"warning": "WIP",
|
||||
"doc_url": "",#2.8 > 2.82 : "wiki_url":"",
|
||||
"category": "3D View",
|
||||
}
|
||||
# bl_info = {
|
||||
# "name": "GP guided colorize",
|
||||
# "description": "Grease pencil colorisation helpers",
|
||||
# "author": "Samuel Bernou",
|
||||
# "version": (0, 1, 0),
|
||||
# "blender": (2, 82, 0),
|
||||
# "location": "3D view > Gpencil > Colorize",
|
||||
# "warning": "WIP",
|
||||
# "doc_url": "",
|
||||
# "category": "3D View",
|
||||
# }
|
||||
|
||||
import bpy
|
||||
from . import OP_gmic
|
||||
# from .OP_gmic import (GMICOLOR_OT_propagate_spots,
|
||||
# GMICOLOR_OT_clear_cam_bg_images,
|
||||
# GMICOLOR_OT_open_gmic_tool_folder,
|
||||
# GMICOLOR_PT_auto_color_panel,)
|
||||
|
||||
from . import OP_line_closer
|
||||
from . import OP_create_empty_frames
|
||||
# from .OP_line_closer import (GPSTK_OT_extend_lines,
|
||||
# GPSTK_PT_line_closer_panel,
|
||||
# GPSTK_OT_comma_finder,)
|
||||
|
||||
|
||||
## Colorize properties
|
||||
class GPCOLOR_PG_settings(bpy.types.PropertyGroup) :
|
||||
res_percentage: bpy.props.IntProperty(
|
||||
name="Gmic out resolution", description="Overrides resolution percentage for playblast", default = 50, min=1, max=200, soft_min=10, soft_max=100, subtype='PERCENTAGE')#, precision=0
|
||||
|
||||
class GPCOLOR_PG_settings(bpy.types.PropertyGroup) :
|
||||
# extend_layers: bpy.props.BoolProperty(name='Extend layers' default=True, description="Work on selected layers, else only active")
|
||||
extend_layer_tgt : bpy.props.EnumProperty(
|
||||
name="Extend layers", description="Choose which layer to target",
|
||||
|
@ -47,14 +37,8 @@ class GPCOLOR_PG_settings(bpy.types.PropertyGroup) :
|
|||
name="Deviation angle", description="Deviation angle tolerance of last point(s) to be considered accidental trace",
|
||||
default=1.22, min=0.017, max=3.124, soft_min=0.017, soft_max=1.92, step=3, precision=2, unit='ROTATION')#, subtype='ANGLE')
|
||||
|
||||
|
||||
|
||||
classes = (
|
||||
GPCOLOR_PG_settings,
|
||||
# GMICOLOR_OT_propagate_spots,
|
||||
# GMICOLOR_OT_clear_cam_bg_images,
|
||||
# GMICOLOR_OT_open_gmic_tool_folder,
|
||||
# GMICOLOR_PT_auto_color_panel,
|
||||
)
|
||||
|
||||
def register():
|
||||
|
@ -62,11 +46,9 @@ def register():
|
|||
bpy.utils.register_class(cls)
|
||||
OP_create_empty_frames.register()
|
||||
OP_line_closer.register()
|
||||
OP_gmic.register()
|
||||
bpy.types.Scene.gpcolor_props = bpy.props.PointerProperty(type = GPCOLOR_PG_settings)
|
||||
|
||||
def unregister():
|
||||
OP_gmic.unregister()
|
||||
OP_line_closer.unregister()
|
||||
OP_create_empty_frames.unregister()
|
||||
for cls in reversed(classes):
|
||||
|
|
|
@ -1,424 +0,0 @@
|
|||
from .func_gmic import *
|
||||
from ..utils import get_addon_prefs, open_folder
|
||||
import bpy
|
||||
from os.path import join, basename, exists, dirname, abspath, splitext
|
||||
|
||||
'''#decorator mod
|
||||
def with_renderfile(filepath):
|
||||
def with_renderfile_decorator(func):
|
||||
def decorator(*args, **kwargs):
|
||||
r = bpy.context.scene.render
|
||||
old_filepath, r.filepath = r.filepath, filepath
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
finally:
|
||||
r.filepath = old_filepath
|
||||
|
||||
return decorator
|
||||
|
||||
return with_renderfile_decorator
|
||||
|
||||
@with_renderfile("//myfile")
|
||||
'''
|
||||
|
||||
# self with implementation
|
||||
def render_filepath(filepath):
|
||||
class RenderFileRestorer:
|
||||
|
||||
def __enter__(self):
|
||||
bpy.context.scene.render.film_transparent = True
|
||||
bpy.context.scene.render.filepath = filepath
|
||||
bpy.context.scene.render.resolution_percentage = bpy.context.scene.gpcolor_props.res_percentage
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
bpy.context.scene.render.filepath = old_filepath
|
||||
bpy.context.scene.render.film_transparent = transparent
|
||||
bpy.context.scene.render.resolution_percentage = old_res
|
||||
|
||||
transparent = bpy.context.scene.render.film_transparent
|
||||
old_filepath = bpy.context.scene.render.filepath
|
||||
old_res = bpy.context.scene.render.resolution_percentage
|
||||
return RenderFileRestorer()
|
||||
|
||||
|
||||
def layer_state(gp_data):
|
||||
class LayerStateRestorer:
|
||||
|
||||
def __enter__(self):
|
||||
# mask/restore other GP object ?
|
||||
self.layers_state = {l:l.hide for l in gp_data.layers}
|
||||
|
||||
def __exit__(self, type, value, traceback):
|
||||
for k, v in self.layers_state.items():
|
||||
k.hide = v
|
||||
|
||||
return LayerStateRestorer()
|
||||
|
||||
def cursor_state():
|
||||
class CursorStateRestorer:
|
||||
|
||||
def __enter__(self):
|
||||
...
|
||||
def __exit__(self, type, value, traceback):
|
||||
bpy.context.window_manager.progress_end()
|
||||
|
||||
return CursorStateRestorer()
|
||||
|
||||
def imtool_fp(dest='tool',name=None):
|
||||
if name:
|
||||
return join(bpy.path.abspath('//'), dest, name)
|
||||
return join(bpy.path.abspath('//'), dest)
|
||||
|
||||
def generate_seq_placeholder():
|
||||
with cursor_state():
|
||||
wm = bpy.context.window_manager
|
||||
wm.progress_begin(bpy.context.scene.frame_start, bpy.context.scene.frame_end)
|
||||
for i in range(bpy.context.scene.frame_start,bpy.context.scene.frame_end+1):
|
||||
fp = imtool_fp(name = f'colotmp_{str(i).zfill(4)}.png')
|
||||
wm.progress_update(i)#remap from frame range to 0-1000 with transfer_value(Value, OldMin, OldMax, NewMin, NewMax)
|
||||
if not exists(fp):
|
||||
generate_empty_image(fp)
|
||||
|
||||
def set_bg_img_settings(bgimg):
|
||||
bgimg.display_depth = 'FRONT' if bpy.data.version[1] < 83 else 'BACK'
|
||||
bgimg.alpha = 0.6
|
||||
bgimg.frame_method = 'FIT'#'STRETCH'
|
||||
|
||||
|
||||
def load_bg_image(colo_fp):
|
||||
# load new image in camera background
|
||||
cam = bpy.context.scene.camera.data
|
||||
cam.show_background_images = True
|
||||
|
||||
colo = basename(colo_fp)
|
||||
colo_img = bpy.data.images.get(colo)
|
||||
|
||||
# load as images
|
||||
if colo_img:
|
||||
colo_img.reload()
|
||||
else:
|
||||
if not exists(colo_fp):return
|
||||
colo_img = bpy.data.images.load(colo_fp)
|
||||
|
||||
bgimg = None
|
||||
for bg in cam.background_images:
|
||||
if bg.image == colo_img:
|
||||
bgimg = bg
|
||||
break
|
||||
|
||||
if not bgimg:
|
||||
bgimg = cam.background_images.new()
|
||||
bgimg.image = colo_img
|
||||
|
||||
set_bg_img_settings(bgimg)
|
||||
return bgimg
|
||||
|
||||
def load_bg_movieclip():
|
||||
# load new image in camera background
|
||||
cam = bpy.context.scene.camera.data
|
||||
cam.show_background_images = True
|
||||
|
||||
## load first image
|
||||
colo = f'colotmp_{str(bpy.context.scene.frame_start).zfill(4)}.png'
|
||||
colo_fp = join(imtool_fp(), colo)
|
||||
if not exists(colo_fp):
|
||||
try:
|
||||
generate_empty_image(colo_fp)
|
||||
pass
|
||||
# TODO generate empty alpha image with GMIC or fast lib (numpy ?)
|
||||
except Exception as identifier:
|
||||
print('In load_bg_movieclip')
|
||||
print(f'NOT FOUND : {colo_fp}')
|
||||
return
|
||||
return
|
||||
|
||||
# load as movie clip
|
||||
colo_img = bpy.data.movieclips.get(colo)
|
||||
if colo_img:
|
||||
pass# colo_img.reload()# video has no reload prop
|
||||
#TODO find a way to trigger refresh automagically !!
|
||||
else:
|
||||
if not exists(colo_fp):return
|
||||
colo_img = bpy.data.movieclips.load(colo_fp)
|
||||
|
||||
bgimg = None
|
||||
for bg in cam.background_images:
|
||||
if bg.clip == colo_img:
|
||||
bgimg = bg
|
||||
break
|
||||
|
||||
if not bgimg:
|
||||
bgimg = cam.background_images.new()
|
||||
bgimg.source = 'MOVIE_CLIP'
|
||||
bgimg.clip = colo_img
|
||||
|
||||
set_bg_img_settings(bgimg)
|
||||
return bgimg
|
||||
|
||||
|
||||
def guide_color(anim=False):
|
||||
'''render lines and spots separately > gmic > feeback into cam background'''
|
||||
scene = bpy.context.scene
|
||||
#### other solution
|
||||
### how about conerting polylines to stroke under the hood with opencv in camera space according to layer
|
||||
### then feed generated array to gmic, might be faster (but dont take stroke thickness into account... problem or feature ?)
|
||||
|
||||
# Generate temporary (local for speed) folder or render in /tmp if not specified ?
|
||||
if not bpy.context.object or bpy.context.object.type != 'GPENCIL': return 1
|
||||
|
||||
gp = bpy.context.object.data
|
||||
frame = str(scene.frame_current).zfill(4)
|
||||
line = f"line_{frame}.png"
|
||||
spot = f"spot_{frame}.png"
|
||||
colo = f"colotmp_{frame}.png"
|
||||
with layer_state(gp):
|
||||
# show/hide layers to render lines/spots only
|
||||
for l in gp.layers:
|
||||
l.hide = any(x in l.info for x in ('spot', 'colo'))#keep only lines
|
||||
# better hide by material namespace ?
|
||||
|
||||
with render_filepath(f"//tool/{line}"):
|
||||
bpy.ops.render.render(animation = anim, write_still=True)
|
||||
|
||||
# show/hide layers to render spots only
|
||||
for l in gp.layers:
|
||||
l.hide = 'spot' not in l.info#keep only spots
|
||||
|
||||
with render_filepath(f"//tool/{spot}"):
|
||||
bpy.ops.render.render(animation = anim, write_still=True)
|
||||
line_fp = join(imtool_fp(), line)
|
||||
spot_fp = join(imtool_fp(), spot)
|
||||
colo_fp = join(imtool_fp(), colo)
|
||||
|
||||
propagate_color(line_fp, spot_fp, colo_fp)
|
||||
## ~4.6sec
|
||||
|
||||
|
||||
# now try and check if openCV or gmic can smooth vectorize the stuff
|
||||
|
||||
## ! surely possible to avoid writting the file like giving it back as a numpy array and keep it within blender !
|
||||
## >> just feed numpy array to gmic and get output ?
|
||||
## Again maybe possible to avoid writing to disk but more complicated to send to gmic (use slot 8 and 9 ?)
|
||||
|
||||
# clear line/spot render if necessary...
|
||||
|
||||
|
||||
class GMICOLOR_OT_propagate_spots(bpy.types.Operator):
|
||||
"""
|
||||
Propagate the spots with a gmic call
|
||||
use shift+clic to force reload after operation.
|
||||
"""
|
||||
bl_idname = "bgmic.propagate_color"
|
||||
bl_label = "Gmic propagate color"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.active_object is not None and context.active_object.type == 'GPENCIL'
|
||||
|
||||
anim : bpy.props.BoolProperty(
|
||||
name="animation", description="render and propagate color for whole animation", default=False, subtype='NONE', options={'ANIMATABLE'})#HIDDEN
|
||||
|
||||
## TODO set preview mode (with low percentage)
|
||||
|
||||
# subtype (string) – Enumerator in ['FILE_PATH', 'DIR_PATH', 'FILE_NAME', 'BYTE_STRING', 'PASSWORD', 'NONE'].
|
||||
# options (set) – Enumerator in ['HIDDEN', 'SKIP_SAVE', 'ANIMATABLE', 'LIBRARY_EDITABLE', 'PROPORTIONAL','TEXTEDIT_UPDATE'].
|
||||
mode : bpy.props.StringProperty(
|
||||
name="mode", description="Set mode for operator", default="render", maxlen=0, subtype='NONE', options={'ANIMATABLE'})
|
||||
|
||||
load : bpy.props.BoolProperty(default=False)
|
||||
|
||||
def execute(self, context):
|
||||
## TODO make a warning if animation mode is on and there is a consequent number of frame with big resolutions...
|
||||
frame = str(context.scene.frame_current).zfill(4)
|
||||
colo = f'colotmp_{frame}.png'
|
||||
colo_fp = join(imtool_fp(), colo)
|
||||
bgimg = None
|
||||
|
||||
## render one image or full-anim
|
||||
if self.mode == 'render':
|
||||
## Or maybe use the technique of BG rendering... with subprocess call
|
||||
bgimg = guide_color(self.anim)
|
||||
|
||||
|
||||
## re-load
|
||||
if self.mode == 'load' or self.load:
|
||||
""" if not exists(colo_fp):
|
||||
print(f'/!\\ {frame}: color was not generated')
|
||||
return {'CANCELLED'} """
|
||||
bpy.ops.bgmic.clear_cam_bg_images(real_clear=False)#clear before load
|
||||
if self.anim:
|
||||
bgimg = load_bg_movieclip()
|
||||
generate_seq_placeholder()#generate all placeholders
|
||||
else:
|
||||
bgimg = load_bg_image(colo_fp)
|
||||
|
||||
if not bgimg:
|
||||
mess = f"Not Found, Loading {'anim' if self.anim else 'image'} has failed at {dirname(colo_fp)}"
|
||||
self.report({'ERROR'}, mess)#WARNING, ERROR
|
||||
return {'CANCELLED'}
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.load = event.shift#if shift is pressed, force inclusion of load
|
||||
return self.execute(context)
|
||||
|
||||
class GMICOLOR_OT_clear_cam_bg_images(bpy.types.Operator):
|
||||
"""
|
||||
Disable and clear background images from scene camera (mask non spot imgs)
|
||||
Shift+clic for a real clear (delete all refs images from camera bg images)
|
||||
"""
|
||||
bl_idname = "bgmic.clear_cam_bg_images"
|
||||
bl_label = "Clear camera background color images"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.scene.camera
|
||||
|
||||
real_clear : bpy.props.BoolProperty(default=False)
|
||||
|
||||
def execute(self, context):
|
||||
# TODO be selective to user cam (filter on name)
|
||||
# TODO need to delete only "spot" name instead of full clear
|
||||
if self.real_clear:
|
||||
context.scene.camera.data.background_images.clear()
|
||||
else:
|
||||
to_del = []
|
||||
for bgimg in context.scene.camera.data.background_images:
|
||||
if bgimg.source == 'MOVIE_CLIP':
|
||||
if not bgimg.clip or 'spot' in bgimg.clip.name or 'colotmp' in bgimg.clip.name:
|
||||
to_del.append(bgimg)
|
||||
continue
|
||||
else:#just hide
|
||||
bgimg.show_background_image = False
|
||||
else:
|
||||
if not bgimg.image or 'spot' in bgimg.image.name or 'colotmp' in bgimg.image.name:
|
||||
to_del.append(bgimg)
|
||||
continue
|
||||
else:#just hide
|
||||
bgimg.show_background_image = False
|
||||
|
||||
for bimg in reversed(to_del):
|
||||
context.scene.camera.data.background_images.remove(bimg)
|
||||
|
||||
|
||||
context.scene.camera.data.show_background_images = False#toggle off then on to force refresh
|
||||
# context.scene.camera.data.show_background_images = True
|
||||
return {'FINISHED'}
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.real_clear = event.shift#if shift is pressed, force inclusion of load
|
||||
return self.execute(context)
|
||||
|
||||
class GMICOLOR_OT_open_gmic_tool_folder(bpy.types.Operator):
|
||||
"""
|
||||
Disable and clear background images from scene camera (mask non spot imgs)
|
||||
Shift+clic for a real clear (delete all refs images from camera bg images)
|
||||
"""
|
||||
bl_idname = "bgmic.open_gmic_tool_folder"
|
||||
bl_label = "Open spot-image-tool Folder"
|
||||
bl_options = {'REGISTER', 'INTERNAL'}
|
||||
|
||||
def execute(self, context):
|
||||
fp = join(bpy.path.abspath('//'), 'tool')
|
||||
if not exists(fp):
|
||||
mess = f'{fp} not found'
|
||||
self.report({'WARNING'}, mess)
|
||||
return {'CANCELLED'}
|
||||
|
||||
open_folder(fp)
|
||||
self.report({'INFO'}, 'Gmic tool folder opened')
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
## base panel
|
||||
class GMICOLOR_PT_auto_color_panel(bpy.types.Panel):
|
||||
bl_label = "GP Colorize"# title
|
||||
# bl_parent_id # If set, the panel becomes a sub-panel
|
||||
|
||||
## bl_options = {'DEFAULT_CLOSED', 'HIDE_HEADER' }# closed by default, collapse the panel and the label
|
||||
## is_popover = False # if ommited
|
||||
## bl_space_type = ['EMPTY', 'VIEW_3D', 'IMAGE_EDITOR', 'NODE_EDITOR', 'SEQUENCE_EDITOR', 'CLIP_EDITOR', 'DOPESHEET_EDITOR', 'GRAPH_EDITOR', 'NLA_EDITOR', 'TEXT_EDITOR', 'CONSOLE', 'INFO', 'TOPBAR', 'STATUSBAR', 'OUTLINER', 'PROPERTIES', 'FILE_BROWSER', 'PREFERENCES'], default 'EMPTY'
|
||||
|
||||
bl_space_type = "VIEW_3D"
|
||||
bl_region_type = "UI"
|
||||
bl_category = "Gpencil"#name of the tab
|
||||
|
||||
|
||||
# activating on some context only
|
||||
## bl_context : object, objectmode, mesh_edit, curve_edit, surface_edit, text_edit, armature_edit, mball_edit, lattice_edit, pose_mode, imagepaint, weightpaint, vertexpaint, particlemode
|
||||
#bl_context = "objectmode"#render
|
||||
|
||||
#need to be in object mode
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return get_addon_prefs().use_color_tools#(context.object is not None and context.object.type == 'GPENCIL')
|
||||
|
||||
## draw stuff inside the header (place before main label)
|
||||
# def draw_header(self, context):
|
||||
# layout = self.layout
|
||||
# layout.label(text="More text in header")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
prefs = get_addon_prefs()
|
||||
if not prefs.gmic_path:
|
||||
layout.label(text='Gmic path missing in addon prefs', icon='ERROR')
|
||||
return
|
||||
|
||||
if not [l for l in context.object.data.layers if 'spot' in l.info]:
|
||||
layout.label(text='Need at least one spots layer !', icon='ERROR')
|
||||
layout.label(text='("spot" in name to identify)')
|
||||
return
|
||||
# row = layout.row()
|
||||
layout.prop(context.scene.gpcolor_props, 'res_percentage')
|
||||
|
||||
## render and load frame
|
||||
ops = layout.operator("bgmic.propagate_color", icon = 'FILE_IMAGE')
|
||||
ops.mode = 'render'
|
||||
ops.anim = False
|
||||
|
||||
## render and load anim
|
||||
ops = layout.operator("bgmic.propagate_color", text='Gmic propagate animation', icon = 'FILE_MOVIE')
|
||||
ops.mode = 'render'
|
||||
ops.anim = True
|
||||
|
||||
layout.separator()
|
||||
|
||||
## Load frame
|
||||
ops = layout.operator("bgmic.propagate_color", text='load frame', icon = 'FILE_IMAGE')
|
||||
ops.mode = 'load'
|
||||
ops.anim = False
|
||||
|
||||
## Load anim
|
||||
ops = layout.operator("bgmic.propagate_color", text='Load animation', icon = 'FILE_MOVIE')
|
||||
ops.mode = 'load'
|
||||
ops.anim = True
|
||||
|
||||
layout.separator()
|
||||
layout.operator("bgmic.clear_cam_bg_images")
|
||||
|
||||
## Open gmic tool location
|
||||
layout.operator("bgmic.open_gmic_tool_folder", icon = 'FILE_FOLDER')#, text='Open img tool folder'
|
||||
|
||||
|
||||
## TODO : Add an operator to generate empty alpha image to avoid the pink flashes...
|
||||
## todo : choose to overwrite or not
|
||||
## Add button to delete current "frame" (delete image on disk...)
|
||||
|
||||
|
||||
classes = (
|
||||
GMICOLOR_OT_propagate_spots,
|
||||
GMICOLOR_OT_clear_cam_bg_images,
|
||||
GMICOLOR_OT_open_gmic_tool_folder,
|
||||
GMICOLOR_PT_auto_color_panel,
|
||||
)
|
||||
|
||||
def register():
|
||||
for cls in classes:
|
||||
bpy.utils.register_class(cls)
|
||||
|
||||
def unregister():
|
||||
for cls in reversed(classes):
|
||||
bpy.utils.unregister_class(cls)
|
|
@ -1,4 +1,4 @@
|
|||
from .func_gmic import *
|
||||
# from .func_gmic import *
|
||||
from ..utils import (location_to_region,
|
||||
region_to_location,
|
||||
vector_length_2d,
|
||||
|
|
|
@ -1,184 +0,0 @@
|
|||
import os, re
|
||||
from os.path import join, basename, exists, dirname, abspath, splitext
|
||||
import subprocess
|
||||
import time, datetime
|
||||
|
||||
from ..utils import get_addon_prefs, transfer_value
|
||||
|
||||
def get_gmic():
|
||||
prefs = get_addon_prefs()
|
||||
return prefs.gmic_path
|
||||
|
||||
|
||||
## globals
|
||||
image_exts = ('.png', '.jpg', '.tiff', '.tga', '.jpeg',)
|
||||
Rnum = re.compile(r'(\d+)(?!.*\d)')
|
||||
|
||||
def is_img(fp):
|
||||
if splitext(basename(fp))[1].lower() in image_exts:
|
||||
return True
|
||||
|
||||
def is_img_folder(d):
|
||||
ct = 0
|
||||
for f in os.listdir(d):
|
||||
ct += 1
|
||||
#if os.path.isfile(d)
|
||||
if not is_img(f):
|
||||
#print("not an image:", f)#Dbg
|
||||
return 0
|
||||
|
||||
if not ct:#return false if nothing found
|
||||
#print('nothing in folder')
|
||||
return -1
|
||||
|
||||
###all files has been evaluated as images
|
||||
return 1
|
||||
|
||||
|
||||
def auto_colo(line, colo, out):
|
||||
gmic = get_gmic()
|
||||
opt = r'fx_colorize_lineart_smart 2,96,0,0,0,1,24,197,0,90.4,1,34.05,22.27,48.96,0.57,6.4,1,0,20,50.18,7.5,0.5,0'
|
||||
if not exists(line) or not exists(colo):
|
||||
print('one source directory not exists')
|
||||
return
|
||||
|
||||
line_l = [join(line, i) for i in os.listdir(line) if i.endswith(('.png', '.jpg'))]
|
||||
colo_l = [join(colo, i) for i in os.listdir(colo) if i.endswith(('.png', '.jpg'))]
|
||||
line_l.sort()
|
||||
colo_l.sort()
|
||||
|
||||
#print(line_l)
|
||||
#print(colo_l)
|
||||
|
||||
if len(line_l) != len(colo_l):
|
||||
print('lists of line and colo files have not the same lenght')
|
||||
return
|
||||
|
||||
outfolder_name = basename(dirname(line)) + '_autocolo'
|
||||
outfolder = join(out, outfolder_name)
|
||||
if not exists(outfolder):
|
||||
os.mkdir(outfolder)
|
||||
|
||||
ct = 0
|
||||
for i, f in enumerate(line_l):
|
||||
ct += 1
|
||||
filename = outfolder_name + '_'+ str(i+101).zfill(4) +'.png'
|
||||
outfile = join(outfolder, filename)
|
||||
#print('-', f,outfile)
|
||||
cmd = '{} {} {} {} -o[1] {}'.format(gmic, line_l[i], colo_l[i], opt, outfile)
|
||||
#note on -o[1]
|
||||
#this filter output 2 img, original line and the new color, here specify only color (keep your name clean)
|
||||
print(cmd)
|
||||
os.system(cmd)
|
||||
# if ct > 3:return#limiter
|
||||
|
||||
print('Done')
|
||||
|
||||
|
||||
def random_fill(line, out):
|
||||
'''gmic command to convert line file to pseudo color out file'''
|
||||
gmic = get_gmic()
|
||||
#Todo, handle png compression, will be deleted so can be uncompressed
|
||||
start_time = time.time()#timer
|
||||
opt = r'fx_colorize_lineart_smart 0,100,0,0,0,80,184,0,90.5,2,0,0,0,0,4,1,2'
|
||||
cmd = [gmic, line] + opt.split(' ') + ['-o[1]', out]# + ['to_rgba']
|
||||
print(cmd)
|
||||
subprocess.call(cmd)
|
||||
print("elapsed", time.time() - start_time)#timer
|
||||
|
||||
def random_fill_folder(src, dest):
|
||||
'''gmic command to convert a line folder to pseudo color output in another folder'''
|
||||
# opt = r'fx_colorize_lineart_smart 0,97.2,0,0,0,0,210,213,0,86.5,1,49.41,28.67,37.26,0.29,12.7,0,0,0,0,0,0,0'
|
||||
if not exists(src):
|
||||
print('source directory not exists')
|
||||
return
|
||||
|
||||
line_l = [join(src, i) for i in os.listdir(src) if is_img(i)]
|
||||
line_l.sort()
|
||||
|
||||
'''
|
||||
outfolder_name = basename(dirname(src)) + '_randomcolo'
|
||||
outfolder = join(dest, outfolder_name)
|
||||
if not exists(outfolder):
|
||||
os.mkdir(outfolder)
|
||||
'''
|
||||
|
||||
#ct = 0
|
||||
for i, f in enumerate(line_l):
|
||||
outfile = join(dest, 'random_fill_' + str(i+101).zfill(4) +'.png')
|
||||
random_fill(f, outfile)
|
||||
|
||||
print('Done')
|
||||
|
||||
def generate_empty_image(fp):
|
||||
'''
|
||||
Generate an empty 1x1 pixel full transparent
|
||||
width,height,depth,spectrum(channels)
|
||||
doc: https://gmic.eu/tutorial/_input.shtml
|
||||
generate a file of ~200byte
|
||||
'''
|
||||
gmic = get_gmic()
|
||||
cmd = [gmic, '1,1,1,4', '-o', fp]
|
||||
# cmd = [gmic, '16,9,1,4', '-o', fp] #classic ratio... influence nothing
|
||||
subprocess.call(cmd)
|
||||
|
||||
def propagate_color(line, spot, out):
|
||||
gmic = get_gmic()
|
||||
start_time = time.time()#timer
|
||||
## colorize
|
||||
opt = ['fx_colorize_lineart', '1,3,0,0.02']
|
||||
|
||||
## antialias
|
||||
aa = ['fx_smooth_antialias', '10,10.1,1.22,0,50,50']# smooth aa
|
||||
# aa = ['gcd_anti_alias', '60,0.1,0,0']# basic aa
|
||||
|
||||
## BG remove
|
||||
# vert pur 0,255,0,255 for BG color to delete, rose pale : [234,139,147,255] : [0.822786, 0.258183, 0.291771, 1.000000] #EA8B93
|
||||
# 2 first value tolerance(1~3),smoothness(need0)
|
||||
del_bg = ['to_rgba', 'replace_color', '3,0,1,255,1,255,255,255,255,0']
|
||||
print('gmic: ', gmic)
|
||||
# gmic = f'"{gmic}"'
|
||||
cmd = [gmic, line, spot] + opt + del_bg + ['-o[1]', out]# + aa
|
||||
print('cmd: ', cmd)
|
||||
subprocess.call(cmd)
|
||||
print("elapsed", time.time() - start_time)#timer
|
||||
|
||||
|
||||
|
||||
def propagate_color_folder(line_fp, spot_fp, outfolder):
|
||||
print('Starting', datetime.datetime.now())# print full current date
|
||||
start_time = time.time()# get start time
|
||||
|
||||
|
||||
# [gmic_krita_qt]./apply/ v -99 fx_colorize_lineart 1,3,0,0.02
|
||||
if not exists(line_fp) or not exists(spot_fp) or not exists(outfolder):
|
||||
print(f'''some directories not exists:
|
||||
{exists(line_fp)}: {line_fp}
|
||||
{exists(spot_fp)}: {spot_fp}
|
||||
{exists(outfolder)}: {outfolder}''')
|
||||
return 1
|
||||
|
||||
lines = sorted([f.path for f in os.scandir(line_fp) if is_img(f.name) and Rnum.search(f.name)])
|
||||
spots = sorted([f.path for f in os.scandir(spot_fp) if is_img(f.name) and Rnum.search(f.name)])
|
||||
|
||||
# if len(lines) != len(spots):#file number test...valid but disabled for tests
|
||||
# print('lists of line and colo files have not the same lenght')
|
||||
# return
|
||||
|
||||
for l, s in zip(lines, spots):
|
||||
lframe = int(Rnum.search(l).group(1))
|
||||
sframe = int(Rnum.search(s).group(1))
|
||||
if lframe != sframe:
|
||||
print(f'line img has not the same number as spot img {lframe} != {sframe}')
|
||||
continue
|
||||
|
||||
out = join(outfolder, f'colo_{str(lframe).zfill(3)}.png')
|
||||
|
||||
print(f'frame {lframe}')
|
||||
propagate_color(l,s,out)
|
||||
|
||||
elapsed_time = time.time() - start_time# seconds
|
||||
full_time = str(datetime.timedelta(seconds=elapsed_time))# hh:mm:ss format
|
||||
|
||||
print("elapsed time", elapsed_time)
|
||||
print(full_time)
|
|
@ -11,20 +11,19 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
## basec on GPclipboard 1.3.1 (without addon prefs)
|
||||
## based on GPclipboard 1.3.2 (just stripped addon prefs)
|
||||
|
||||
bl_info = {
|
||||
"name": "GP clipboard",
|
||||
"description": "Copy/Cut/Paste Grease Pencil strokes to/from OS clipboard across layers and blends",
|
||||
"author": "Samuel Bernou",
|
||||
"version": (1, 3, 1),
|
||||
"version": (1, 3, 2),
|
||||
"blender": (2, 83, 0),
|
||||
"location": "View3D > Toolbar > Gpencil > GP clipboard",
|
||||
"warning": "",
|
||||
"doc_url": "https://github.com/Pullusb/GP_clipboard",
|
||||
"category": "Object" }
|
||||
|
||||
|
||||
import bpy
|
||||
import os
|
||||
import mathutils
|
||||
|
@ -96,9 +95,12 @@ def dump_gp_stroke_range(s, sid, l, obj):
|
|||
if s.material_index != 0:
|
||||
sdic['material_index'] = s.material_index
|
||||
|
||||
if s.draw_cyclic:
|
||||
if getattr(s, 'draw_cyclic', None):# pre-2.92
|
||||
sdic['draw_cyclic'] = s.draw_cyclic
|
||||
|
||||
if getattr(s, 'use_cyclic', None):# from 2.92
|
||||
sdic['use_cyclic'] = s.use_cyclic
|
||||
|
||||
if s.uv_scale != 1.0:
|
||||
sdic['uv_scale'] = s.uv_scale
|
||||
|
||||
|
@ -677,10 +679,8 @@ def register_keymaps():
|
|||
addon_keymaps.append((km, kmi))
|
||||
|
||||
def unregister_keymaps():
|
||||
# wm = bpy.context.window_manager
|
||||
for km, kmi in addon_keymaps:
|
||||
km.keymap_items.remove(kmi)
|
||||
# wm.keyconfigs.addon.keymaps.remove(km)
|
||||
addon_keymaps.clear()
|
||||
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ class GPTB_OT_file_checker(bpy.types.Operator):
|
|||
|
||||
## set scene res at pref res according to addon pref
|
||||
rx, ry = prefs.render_res_x, prefs.render_res_y
|
||||
# TODO set (rx, ry) to camera resolution if specified in camera name
|
||||
if context.scene.render.resolution_x != rx or context.scene.render.resolution_y != ry:
|
||||
problems.append(f'Resolution {context.scene.render.resolution_x}x{context.scene.render.resolution_y} >> {rx}x{ry}')
|
||||
context.scene.render.resolution_x, context.scene.render.resolution_y = rx, ry
|
||||
|
|
32
README.md
32
README.md
|
@ -2,15 +2,16 @@
|
|||
|
||||
Blender addon - Various tool to help with grease pencil in animation productions.
|
||||
|
||||
**[Download latest](https://gitlab.com/autour-de-minuit/blender/GP_toolbox/-/archive/master/GP_toolbox-master.zi)**
|
||||
**[Download latest](https://gitlab.com/autour-de-minuit/blender/gp_toolbox/-/archive/master/GP_toolbox-master.zip)**
|
||||
|
||||
<!-- ### [Demo Youtube]() -->
|
||||
|
||||
**[Readme Doc in French (Documentation en Français et plus détaillée)](https://gitlab.com/autour-de-minuit/blender/gp_toolbox/-/blob/master/README_FR.md)**
|
||||
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
|
||||
<!-- ![pseudo color demo](https://github.com/Pullusb/images_repo/blob/master/GPT_pseudo_tint.gif)
|
||||
*In this demo F9 is pressed to call the "redo panel" and modify the hue offset with constant update* -->
|
||||
|
||||
|
@ -25,7 +26,7 @@ important point of addon preferences:
|
|||
|
||||
Set path to the palette folder (there is a json palette IO but you an also put a blend and use a blend importer)
|
||||
|
||||
Note about palette : For now thoe importer are not working with linked palette is not easy for animator (there are properies of the material you cannot access and the link grey-out fade the r eal color in UIlist preview)
|
||||
Note about palette : For now the importer is not working with linked palette as it's not easy for animator (there are properties of the material you cannot access and the link grey-out fade the real color in UIlist preview)
|
||||
|
||||
|
||||
- Mirror flip : If in cam view flip the camera X scale value (you can see and draw mnirrored to see problems)
|
||||
|
@ -66,11 +67,25 @@ Note about palette : For now thoe importer are not working with linked palette i
|
|||
|
||||
Panel in sidebar : 3D view > sidebar 'N' > Gpencil
|
||||
|
||||
<!--
|
||||
|
||||
## Todo:
|
||||
- viewport Face GP object -> test in 3D context tester
|
||||
- move GP keyframes selection and Object keyframe selection simultaneouly (Tom viguier is test)
|
||||
- -->
|
||||
|
||||
- Allow to render resolution from cam name
|
||||
|
||||
- Update multi output system:
|
||||
- use render layers + file outputs instead of batch by tweaking visibility
|
||||
|
||||
- BG Playblast enhancement:
|
||||
- Add a prefs to fallback to "simple" render.
|
||||
|
||||
- Settings-io for projects : Rsolution du film, palette folder, render settings...
|
||||
|
||||
- expose "tool setting" of canvas handling in sidebar (visible only in draw mode)
|
||||
|
||||
- Move automatically view to match GP Front (depending on Gpencil view settings)
|
||||
|
||||
- move GP keyframes selection and Object keyframe selection simultaneouly (Already Done by Tom Viguier at [Andarta](https://gitlab.com/andarta-pictures)
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
@ -82,6 +97,9 @@ Panel in sidebar : 3D view > sidebar 'N' > Gpencil
|
|||
- Public release
|
||||
- prefs: added fps as part of project settings
|
||||
- check file use pref fps value (previously used harcoded 24fps value)
|
||||
- cleanup: Remove wip GMIC-bridge tools that need to be done separately (if needed)
|
||||
- update: apply changes in integrated copy-paste from the last version of standalone addon
|
||||
- doc: Added fully-detailed french readme
|
||||
|
||||
|
||||
0.8.0:
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
# GP toolbox
|
||||
|
||||
Blender addon - Boîte a outils de grease pencil pour la production d'animation.
|
||||
|
||||
**[Télécharger la dernière version](https://gitlab.com/autour-de-minuit/blender/GP_toolbox/-/archive/master/GP_toolbox-master.zip)**
|
||||
|
||||
> Une fois en place un système de mise a jour facilité est accessible dans les préférence (La vérification automatique dde nouvelle mise a jour peut y être activé)
|
||||
|
||||
Il est recommandé de désactiver l'addon natif "Grease pencil tools" car ces outils sont déjà intégré dans la toolbox et risque de créer des conflit.
|
||||
|
||||
## Fonctionnalités et détails
|
||||
|
||||
|
||||
### Exposition dans l'UI de fonction native
|
||||
|
||||
Exposition de certains attribut déjà existant utiles mais trop "loins" dans l'interface
|
||||
|
||||
Expose les options suivantes:
|
||||
|
||||
- Zoom 1:1 - Vue en cam prend le zoom 100% en fonction de la résolution (ops `view3d.zoom_camera_1_to_1`)
|
||||
- Zoom fit - Ajuste la vue pour que la cam soit vue en totalité dans l'écran (ops `view3d.view_center_camera`)
|
||||
- Onion skin - coche des overlays
|
||||
- autolock layer - coche du sous-menu de l'UI list des layers
|
||||
- X-ray - Option `In Front` dans les propriété de l'objet
|
||||
- passepartout de caméra - active-désactive + opactité
|
||||
- liste de boutons pour activer/désactiver les background de caméra (tous ou individuellement) avec icone par type.
|
||||
|
||||
**Edit line opacity** - Il est en réalité pratique de pouvoir cacher l'edit line pour avoir un meilleur aperçu du rendu lors du sculpt par exemple. C'est une option lié au layer. Ce slider appelle une fonction pour affecter tout les layers de tout les objets au lieu de se cantonner au layer courant.
|
||||
|
||||
|
||||
### Tools principaux d'anim:
|
||||
|
||||
|
||||
**Système de Main cam VS draw cam / action cam** : pour permettre le roll du viewport quand on est en vue caméra (sans affecter la caméra def du layout) la draw cam peut être activée. c'est simplement une duplication de la caméra principale (main) parenté a cette dernière et sur laquelle on peut se permettre de faire le roll via rotate canvas (Workaround tant que blender ne permet pas de roll la vue en cam).
|
||||
|
||||
L'action cam (aurait du s'appeler follow_cam) fonctionne sur le principe que la draw sauf qu'elle se parente à l'objet selectionné. le but est de pouvoir suivre un objet en mouvement pour le dessiner en contitnue sans nécessairement désactiver les anims. Concrètement, cette dernière solution est plus clean et sans doute moins galère, c'est ce que les animateurs ont majoritairement utilisé.
|
||||
|
||||
**Rotate canvas** (`ctrl + alt + clic-droit`): différence avec celui intégré a grease pencil tools : la rotation en vue cam n'est possible que si on est dans une caméra de manipulation "manip_cam" pour éviter de caasser l'anim le roll de la cam principale.
|
||||
|
||||
**Box deform** (`Ctrl+T`) : Déformation 4 coins (Peut-être le retirer maintenant qu'il est dans le _Grease pencil tools_ pour éviter les conlfits/redondances, mais d'un autre côté la version intégrée peut éventeullement être customisée et corriger d'éventuel souci, sans attendre les updates de blender, a voir)
|
||||
|
||||
**GP keyframe jump** (raccourci a ajouter manuellement, tant qu'on a pas une keymap anim un minimum standard): Essentiel, permet d'ajouter une ou plusieurs paire de raccourcis pour aller de keyframe en keyframe (filtrage du saut personnalisable). le raccourci doit appeler l'operateur `screen.gp_keyframe_jump`, (en faire un second avec le next décoché pour faire un saut arrière)
|
||||
|
||||
**Breakdown en mode objet** (`Shift+E`) : Breakdown en pourcentage entre les deux keyframes (pose une clé si l’auto-key est actif et utilise le keying set si il est actif). Même comportement et raccourci que le breakdown de bones en pose mode (juste qu'il n'existait bizzarement pas en objet)
|
||||
|
||||
|
||||
**Snap cursor** - Snap le curseur sur le canvas de GP (respecte les paramètres "tool setting" qui définit le comportement du canvas)
|
||||
À placer dans la keymap manuellement pour le moment en utilisant l'id `view3d.cusor_snap` (original `view3d.cursor3d`)
|
||||
|
||||
|
||||
**Playblast** - Create a playblast folder in the blend's folder.
|
||||
in 0.8.0 normal playblast (file still within addon folder) was replaced by bg_playblast (adaptation of samy tichadou's playblaster)
|
||||
|
||||
**GP copy paste** - permet de copier coller les clés en dur.
|
||||
TODO -> vérifier l'intégration. semble avoir des soucis.
|
||||
Pas mal de l'avoir en addon séparé aussi vu qu'il a son propre panel a lui.
|
||||
|
||||
**check files** - série de check écris en dur dans le code. Pratique pour "fixer" rapidement sa scène:
|
||||
- Lock main cam
|
||||
- set scene res to def project res (specified in addon prefs)
|
||||
- set scene percentage at 100:
|
||||
- set show slider and sync range in opened dopesheet
|
||||
- set fps to 24 (need generalisation with addonpref choice)
|
||||
- set select cursor type (according to prefs ?)
|
||||
- GP use additive drawing (else creating a frame in dopesheet makes it blank...)
|
||||
- GP stroke placement/projection check (just warn if your not in 'Front')
|
||||
- Warn if there are some disabled animation (and list datapath)
|
||||
- Set onion skin filter to 'All type' (this became default in blender 2.91, guess who asked ;) )
|
||||
|
||||
|
||||
### moins important
|
||||
|
||||
**Mirror flip X** - Applique simplement un `scale.x -1` sur la cam active (un petit indicateur s'affiche pour indiquer qu'on est en mirror, recliquer sur le bouton permet de rétablir le scale d'origine)
|
||||
|
||||
|
||||
**Cursor Follow** - (Utilise un handler) : ubne fois activé, permet de faire suivre le curseur 3D sur un objet animé.
|
||||
Souci connu: Il y a un décalage d'une frame une fois activé sur un nouvel objet, il suffit de le recaler une fois.
|
||||
|
||||
**Animation manager** - permet d'aciver/désactiver les anims d'objets de tout les objets ou de tout les
|
||||
|
||||
### Présent mais pas utilisés:
|
||||
|
||||
**Sticky key tool**
|
||||
Les raccourci vers des tools temporaires sont très pratique, on peut facilement créer un raccourci qui appelle le tool durant la presion d'un bouton. Cet operator est un modal qui permet de faire la même chose mais en activant simplement le tool si la touche est rapide. (`OP_temp_cutter.py > GPTB_OT_sticky_cutter` idname : `wm.sticky_cutter`)
|
||||
|
||||
|
||||
### À potentiellement mettre de côté/retirer:
|
||||
|
||||
**Tint layer** : Très peu utilisé, permet de mettre une teinte aléatoire par calque afin de les différencier rapidement. Souci de cet opérateurm, il ne faut pas l'utiliser si on utilise les tints de layer car il en change la couleur.
|
||||
|
||||
**Colorize** (gros WIP): un sous ensemble d'outils qui était censé permettre de faire du remplissage bitmap via des color spots en envoyant deux set d'images rendu automatiquement à GMIC en ligne de commande et recalé la séquence de résultat en BG de Cam. Finalement abandonné, pas eu le temps de finir la mise au point (malgré des résultats préliminaires intéressant).
|
||||
Maistrop long a mettre en place, trop hackeu, et surtout c'est dommage de basculer sur du bitmap, la source de couleur doit rester au maximum GP/vecto.
|
||||
|
||||
## colorisation:
|
||||
|
||||
**Line stopper** - Extension des lignes dans un matériaux a part pour améliorer la fermeture des formes. le hack est très simple mais aide beaucoup a fermer les contour pour éviter le leak de l'outils pot de peinture.
|
||||
|
||||
**Create empty frame** - Permet de créer des frames vides sur un calques partout ou il y a des frames sur les calques supérieur (permet de faire un key to key sur le calque actif ensuite sur les key pré-créée pour faire sa colo). C'est pratique à utiliser.
|
||||
En réalité pour quelque chose de plus pratique pour la colo, il suffit d'utiliser le `screen.gp_keyframe_jump` operator en activant le filtre (all layers) : TODO faire un "all layer _above_" ou se baser sur le nouveau filtre natif lié a cet usage depuis blender 2.91
|
||||
|
||||
**Render** chemin de sorties + 2 boutons
|
||||
- layers individually (popup pour selecitonner des layers a render individuellement)
|
||||
- layers grouped (popup pour selectionner des layers a rendre ensemble)
|
||||
- TODO -> Le chemin de base est défini en dur dans le project template
|
||||
`blend.parents[1] / "compo" / "base" / obname / (obname+'_')`
|
||||
-> Basculer vers un chemin personnalisable dans les préférences.
|
||||
TODO -> profiter du système de render layers (per layer) pour faire un meilleur batch renderer.
|
||||
|
||||
|
||||
## tools supplémentaires
|
||||
|
||||
**check links** - (pop une fenêtre) permet de lister les liens de la scène, voir si il y en a des cassés et ouvrir le dossier d'un lien existant.
|
||||
|
||||
|
||||
## raccourci supplémentaires
|
||||
|
||||
Sculpt mode:
|
||||
point/stroke filter shortcut sur `1`, `2`, `3` en toggle (similaire a l'edit mode)
|
||||
|
||||
cursor_GP
|
||||
Surcharge du raccourci curseur 3D pour le snapper à la surface du grease pencil.
|
||||
Raccourci à remplacer manuellement dans la keymap, Pas forcément utile si il n'y a un mix de 2D/3D
|
||||
Le mieux serait d'avoir un raccourci dédié, séparé de celui d'origine...
|
||||
|
||||
---
|
||||
|
||||
TODO:
|
||||
|
||||
- Permettre de rendre avec la résolution spécifié dans le nom de la caméra active
|
||||
(utile dans les projet rendu a la résolution du BG mais ou la résolution finale peut être utilisé pour un bout-a-bout)
|
||||
|
||||
- Update du système de "passes" de rendu:
|
||||
- utiliser des render layers + file outputs au lieux de faire des batchs par opacité
|
||||
|
||||
- BG Playblast enhancement:
|
||||
- Tester davantage le playblast BG
|
||||
- Éventuellement mettre une coche de fallback vers le playblast classique (utile en cas de pépin.
|
||||
|
||||
- Faire un import-export des réglage généraux en json (Déjà une bonne partie du code dans Pipe sync)
|
||||
pour set : Résolution du film, dossier palette, render settings
|
||||
|
||||
- opt: exposer les "tool setting" de placement de canvas en permanence dans la sidebar (visible seulement en draw)
|
||||
|
||||
- Déplacer automatiquement la vue "Face" au GP (en fonction des Gpencil view settings)
|
||||
|
||||
- Déplacer les clés de dopesheet en même temps que les clés de GP (Déjà Créer par Tom Viguier sur [Andarta](https://gitlab.com/andarta-pictures)
|
||||
|
||||
- Meilleure table lumineuse (grosse réflexion et travail en perspective)
|
34
__init__.py
34
__init__.py
|
@ -12,7 +12,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
bl_info = {
|
||||
"name": "GP toolbox",
|
||||
"name": "gp toolbox",
|
||||
"description": "Set of tools for Grease Pencil in animation production",
|
||||
"author": "Samuel Bernou",
|
||||
"version": (0, 9, 1),
|
||||
|
@ -238,18 +238,6 @@ class GPTB_prefs(bpy.types.AddonPreferences):
|
|||
max=10000
|
||||
)
|
||||
|
||||
|
||||
## GMIColor
|
||||
use_color_tools : BoolProperty(
|
||||
name = "Use color tools",
|
||||
description = "Enable guided color tools panel",
|
||||
default = False)
|
||||
|
||||
#-# gmic tools not ready
|
||||
gmic_path : StringProperty(
|
||||
name="Path to gmic", description="Need to specify path to gmic binary to allow color pixel propagation features",
|
||||
default="", subtype='FLIE_PATH')
|
||||
|
||||
## Temp cutter
|
||||
# temp_cutter_use_shortcut: BoolProperty(
|
||||
# name = "Use temp cutter Shortcut",
|
||||
|
@ -279,7 +267,6 @@ class GPTB_prefs(bpy.types.AddonPreferences):
|
|||
row.label(text='Render resolution')
|
||||
row.prop(self, 'render_res_x', text='X')
|
||||
row.prop(self, 'render_res_y', text='Y')
|
||||
|
||||
## Palette
|
||||
box.label(text='Palette library folder:')
|
||||
box.prop(self, 'palette_path')
|
||||
|
@ -332,26 +319,7 @@ class GPTB_prefs(bpy.types.AddonPreferences):
|
|||
|
||||
|
||||
box.prop(self, "render_obj_exclusion", icon='FILTER')#
|
||||
|
||||
|
||||
# if self.pref_tabs == 'GMIC':
|
||||
|
||||
# gmic (Disabled - tool complete WIP)
|
||||
box = layout.box()
|
||||
box.label(text='Colorisation:')
|
||||
box.prop(self, 'use_color_tools')
|
||||
if self.use_color_tools:
|
||||
col = box.column(align=False)
|
||||
## Delete if gmic is unused
|
||||
col.prop(self, 'gmic_path')
|
||||
if not self.gmic_path:
|
||||
box=col.box()
|
||||
box.label(text='Gmic is missing. (needed for pixel color tools)', icon='INFO')
|
||||
row = box.row()
|
||||
row.label(text='1.Download GMIC CLI (Command-line interface) here:')
|
||||
row.operator("wm.url_open", text="Get gmic").url = "https://gmic.eu/download.shtml"
|
||||
box.label(text='2.unzip it somewhere and point to gmic.exe')
|
||||
box.label(text='(If gmic is already in your PATH, just write "gmic")')
|
||||
|
||||
if self.pref_tabs == 'MAN_OPS':
|
||||
# layout.separator()## notes
|
||||
|
|
Loading…
Reference in New Issue