Fix playblast with api changes
2.0.0 - fix: error using playblast (api changes of Blender 3.0+)gpv2
parent
f36b31e3aa
commit
bf60370ab0
|
@ -1,5 +1,9 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
2.0.0
|
||||||
|
|
||||||
|
- fix: error using playblast (api changes of Blender 3.0+)
|
||||||
|
|
||||||
1.9.9
|
1.9.9
|
||||||
|
|
||||||
- fix: Bug setting GP layers actions on/off
|
- fix: Bug setting GP layers actions on/off
|
||||||
|
|
|
@ -40,6 +40,8 @@ exclude = (
|
||||||
'audio_bitrate',
|
'audio_bitrate',
|
||||||
]
|
]
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
'''
|
||||||
def render_with_restore():
|
def render_with_restore():
|
||||||
class RenderFileRestorer:
|
class RenderFileRestorer:
|
||||||
rd = bpy.context.scene.render
|
rd = bpy.context.scene.render
|
||||||
|
@ -80,8 +82,47 @@ def render_with_restore():
|
||||||
|
|
||||||
|
|
||||||
return RenderFileRestorer()
|
return RenderFileRestorer()
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
class render_with_restore:
|
||||||
|
def __init__(self):
|
||||||
|
rd = bpy.context.scene.render
|
||||||
|
im = rd.image_settings
|
||||||
|
ff = rd.ffmpeg
|
||||||
|
# ffmpeg (ff) need to be before image_settings(im) in list
|
||||||
|
# otherwise __exit__ may try to restore settings of image mode in video mode !
|
||||||
|
# ex : "RGBA" not found in ('BW', 'RGB') (will still not stop thx to try block)
|
||||||
|
self.zones = [rd, ff, im]
|
||||||
|
|
||||||
|
self.val_dic = {}
|
||||||
|
self.cam = bpy.context.scene.camera
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
## store attribute of data_path in self.zones list.
|
||||||
|
for data_path in self.zones:
|
||||||
|
self.val_dic[data_path] = {}
|
||||||
|
for attr in dir(data_path):#iterate in attribute of given datapath
|
||||||
|
if attr not in exclude and not attr.startswith('__') and not callable(getattr(data_path, attr)) and not data_path.is_property_readonly(attr):
|
||||||
|
self.val_dic[data_path][attr] = getattr(data_path, attr)
|
||||||
|
|
||||||
|
if self.cam and self.cam.name == 'draw_cam':
|
||||||
|
if self.cam.parent:
|
||||||
|
bpy.context.scene.camera = self.cam.parent
|
||||||
|
|
||||||
|
def __exit__(self, type, value, traceback):
|
||||||
|
## restore attribute from self.zones list
|
||||||
|
for data_path, prop_dic in self.val_dic.items():
|
||||||
|
for attr, val in prop_dic.items():
|
||||||
|
try:
|
||||||
|
setattr(data_path, attr, val)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"/!\ Impossible to re-assign: {attr} = {val}")
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
if self.cam:
|
||||||
|
bpy.context.scene.camera = self.cam
|
||||||
|
|
||||||
def playblast(viewport = False, stamping = True):
|
def playblast(viewport = False, stamping = True):
|
||||||
scn = bpy.context.scene
|
scn = bpy.context.scene
|
||||||
res_factor = scn.gptoolprops.resolution_percentage
|
res_factor = scn.gptoolprops.resolution_percentage
|
||||||
|
@ -91,15 +132,15 @@ def playblast(viewport = False, stamping = True):
|
||||||
### can add propeties for personalisation as toolsetting props
|
### can add propeties for personalisation as toolsetting props
|
||||||
|
|
||||||
rd.resolution_percentage = res_factor
|
rd.resolution_percentage = res_factor
|
||||||
while ( rd.resolution_x * res_factor / 100 ) % 2 != 0:# rd.resolution_percentage
|
while ( rd.resolution_x * res_factor / 100 ) % 2 != 0: # rd.resolution_percentage
|
||||||
rd.resolution_x = rd.resolution_x + 1
|
rd.resolution_x = rd.resolution_x + 1
|
||||||
while ( rd.resolution_y * res_factor / 100 ) % 2 != 0:# rd.resolution_percentage
|
while ( rd.resolution_y * res_factor / 100 ) % 2 != 0: # rd.resolution_percentage
|
||||||
rd.resolution_y = rd.resolution_y + 1
|
rd.resolution_y = rd.resolution_y + 1
|
||||||
|
|
||||||
rd.image_settings.file_format = 'FFMPEG'
|
rd.image_settings.file_format = 'FFMPEG'
|
||||||
ff.format = 'MPEG4'
|
ff.format = 'MPEG4'
|
||||||
ff.codec = 'H264'
|
ff.codec = 'H264'
|
||||||
ff.constant_rate_factor = 'HIGH'# MEDIUM
|
ff.constant_rate_factor = 'HIGH' # MEDIUM
|
||||||
ff.ffmpeg_preset = 'REALTIME'
|
ff.ffmpeg_preset = 'REALTIME'
|
||||||
ff.gopsize = 10
|
ff.gopsize = 10
|
||||||
ff.audio_codec = 'AAC'
|
ff.audio_codec = 'AAC'
|
||||||
|
@ -116,13 +157,13 @@ def playblast(viewport = False, stamping = True):
|
||||||
# mode incermental or just use fulldate (cannot create conflict and filter OK but long name)
|
# mode incermental or just use fulldate (cannot create conflict and filter OK but long name)
|
||||||
blend = Path(bpy.data.filepath)
|
blend = Path(bpy.data.filepath)
|
||||||
date_format = "%Y-%m-%d_%H-%M-%S"
|
date_format = "%Y-%m-%d_%H-%M-%S"
|
||||||
fp = join(blend.parent, "images", f'playblast_{blend.stem}_{strftime(date_format)}.mp4')
|
fp = join(blend.parent, "playblast", f'playblast_{blend.stem}_{strftime(date_format)}.mp4')
|
||||||
|
|
||||||
#may need a properties for choosing location : bpy.types.Scene.qrd_savepath = bpy.props.StringProperty(subtype='DIR_PATH', description="Export location, if not specify, create a 'quick_render' directory aside blend location")#(change defaut name in user_prefernece)
|
#may need a properties for choosing location : bpy.types.Scene.qrd_savepath = bpy.props.StringProperty(subtype='DIR_PATH', description="Export location, if not specify, create a 'quick_render' directory aside blend location")#(change defaut name in user_prefernece)
|
||||||
rd.filepath = fp
|
rd.filepath = fp
|
||||||
rd.use_stamp = stamping# toolsetting.use_stamp# True for playblast
|
rd.use_stamp = stamping# toolsetting.use_stamp# True for playblast
|
||||||
#stamp options
|
#stamp options
|
||||||
rd.stamp_font_size = rd.stamp_font_size * res_factor / 100# rd.resolution_percentage
|
rd.stamp_font_size = int(rd.stamp_font_size * res_factor / 100) # rd.resolution_percentage
|
||||||
|
|
||||||
# bpy.ops.render.render_wrap(use_view=viewport)
|
# bpy.ops.render.render_wrap(use_view=viewport)
|
||||||
### render
|
### render
|
||||||
|
|
|
@ -21,15 +21,20 @@ exclude = (
|
||||||
'bl_rna', 'identifier','name_property','rna_type','properties', 'compare', 'to_string',#basic
|
'bl_rna', 'identifier','name_property','rna_type','properties', 'compare', 'to_string',#basic
|
||||||
)
|
)
|
||||||
|
|
||||||
def delete_file(filepath) :
|
def delete_file(filepath):
|
||||||
try:
|
fp = Path(filepath)
|
||||||
if os.path.isfile(filepath) :
|
if fp.exists() and fp.is_file():
|
||||||
print('removing', filepath)
|
try:
|
||||||
os.remove(filepath)
|
print('removing', fp)
|
||||||
|
fp.unlink(missing_ok=False)
|
||||||
|
# os.remove(fp)
|
||||||
return True
|
return True
|
||||||
except PermissionError:
|
except PermissionError:
|
||||||
print(f'impossible to remove {filepath}')
|
print(f'impossible to remove (permission error): {fp}')
|
||||||
return False
|
return False
|
||||||
|
except FileNotFoundError:
|
||||||
|
print(f'Impossible to remove (file not found error): {fp}')
|
||||||
|
return False
|
||||||
|
|
||||||
# render function
|
# render function
|
||||||
def render_function(cmd, total_frame, scene) :
|
def render_function(cmd, total_frame, scene) :
|
||||||
|
@ -58,7 +63,7 @@ def render_function(cmd, total_frame, scene) :
|
||||||
frame_count += 1
|
frame_count += 1
|
||||||
try :
|
try :
|
||||||
# print('frame_count: ', frame_count, 'total_frame: ', total_frame)
|
# print('frame_count: ', frame_count, 'total_frame: ', total_frame)
|
||||||
bpy.context.window_manager.pblast_completion = frame_count / total_frame * 100
|
bpy.context.window_manager.pblast_completion = int(frame_count / total_frame * 100)
|
||||||
except AttributeError :
|
except AttributeError :
|
||||||
#debug
|
#debug
|
||||||
if debug : print("AttributeError avoided")
|
if debug : print("AttributeError avoided")
|
||||||
|
@ -231,9 +236,7 @@ class BGBLAST_OT_playblast_modal_check(bpy.types.Operator):
|
||||||
|
|
||||||
self.report({'INFO'}, "Render Finished")
|
self.report({'INFO'}, "Render Finished")
|
||||||
|
|
||||||
|
"""
|
||||||
### classic sauce
|
|
||||||
|
|
||||||
def render_with_restore():
|
def render_with_restore():
|
||||||
class RenderFileRestorer:
|
class RenderFileRestorer:
|
||||||
rd = bpy.context.scene.render
|
rd = bpy.context.scene.render
|
||||||
|
@ -266,6 +269,38 @@ def render_with_restore():
|
||||||
print(e)
|
print(e)
|
||||||
|
|
||||||
return RenderFileRestorer()
|
return RenderFileRestorer()
|
||||||
|
"""
|
||||||
|
|
||||||
|
class render_with_restore:
|
||||||
|
def __init__(self):
|
||||||
|
rd = bpy.context.scene.render
|
||||||
|
im = rd.image_settings
|
||||||
|
ff = rd.ffmpeg
|
||||||
|
# ffmpeg (ff) need to be before image_settings(im) in list
|
||||||
|
# otherwise __exit__ may try to restore settings of image mode in video mode !
|
||||||
|
# ex : "RGBA" not found in ('BW', 'RGB') (will still not stop thx to try block)
|
||||||
|
|
||||||
|
self.zones = [rd, ff, im]
|
||||||
|
|
||||||
|
self.val_dic = {}
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
## store attribute of data_path in self.zones list.
|
||||||
|
for data_path in self.zones:
|
||||||
|
self.val_dic[data_path] = {}
|
||||||
|
for attr in dir(data_path):#iterate in attribute of given datapath
|
||||||
|
if attr not in exclude and not attr.startswith('__') and not callable(getattr(data_path, attr)) and not data_path.is_property_readonly(attr):
|
||||||
|
self.val_dic[data_path][attr] = getattr(data_path, attr)
|
||||||
|
|
||||||
|
def __exit__(self, type, value, traceback):
|
||||||
|
## restore attribute from self.zones list
|
||||||
|
for data_path, prop_dic in self.val_dic.items():
|
||||||
|
for attr, val in prop_dic.items():
|
||||||
|
try:
|
||||||
|
setattr(data_path, attr, val)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"/!\ Impossible to re-assign: {attr} = {val}")
|
||||||
|
print(e)
|
||||||
|
|
||||||
|
|
||||||
def playblast(context, viewport = False, stamping = True):
|
def playblast(context, viewport = False, stamping = True):
|
||||||
|
@ -325,7 +360,7 @@ def playblast(context, viewport = False, stamping = True):
|
||||||
rd.filepath = fp
|
rd.filepath = fp
|
||||||
rd.use_stamp = stamping# toolsetting.use_stamp# True for playblast
|
rd.use_stamp = stamping# toolsetting.use_stamp# True for playblast
|
||||||
#stamp options
|
#stamp options
|
||||||
rd.stamp_font_size = rd.stamp_font_size * res_factor / 100# rd.resolution_percentage
|
rd.stamp_font_size = int(rd.stamp_font_size * res_factor / 100) # rd.resolution_percentage
|
||||||
|
|
||||||
|
|
||||||
# get total number of frames
|
# get total number of frames
|
||||||
|
|
19
__init__.py
19
__init__.py
|
@ -1,21 +1,10 @@
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation; either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful, but
|
|
||||||
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
# General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
bl_info = {
|
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": (1, 9, 9),
|
"version": (2, 0, 0),
|
||||||
"blender": (2, 91, 0),
|
"blender": (2, 91, 0),
|
||||||
"location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties",
|
"location": "Sidebar (N menu) > Gpencil > Toolbox / Gpencil properties",
|
||||||
"warning": "",
|
"warning": "",
|
||||||
|
@ -24,14 +13,10 @@ bl_info = {
|
||||||
"category": "3D View",
|
"category": "3D View",
|
||||||
}
|
}
|
||||||
|
|
||||||
# from . import addon_updater_ops
|
|
||||||
|
|
||||||
# from .utils import *
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from shutil import which
|
from shutil import which
|
||||||
from sys import modules
|
from sys import modules
|
||||||
from .utils import get_addon_prefs, draw_kmi
|
from .utils import get_addon_prefs, draw_kmi
|
||||||
# from .functions import *
|
|
||||||
|
|
||||||
## GMIC
|
## GMIC
|
||||||
from .GP_guided_colorize import GP_colorize
|
from .GP_guided_colorize import GP_colorize
|
||||||
|
|
Loading…
Reference in New Issue