2018年1月2日火曜日

アニメの監督がBlenderでコンテを書く本をだしてみえたので・・・

2017年皆様お疲れ様でした
先頃開催されたコミックマーケット93で アニメ監督のりょーちも氏が
Blenderでコンテを書くメイキングを書いた本を出されていたのですが
本を拝見して勝手ながら こういうやり方もあるということをいくつか書き連ねておきます
本の内容で個人的に連想したものであって これが実用にかなうものか分からないのでご注意ください

まずは 監督が頒布されてるデータの紹介
『timosh × blender』本の中で紹介したひな型データ
本ではこちらのconte_v1.blendの3Dビュー上でグリースペンシルで時間軸に沿って絵を描き
ファイルに内蔵しているスクリプトを実行することで
レンダリングした画像を コンテ撮(コンテから作った動画でアフレコ等をする)や従来の紙コンテ画像にする方法を解説されています
(因みに12/31現在ダウンロードファイルのOpenglレンダリング部分(69行目)がコメントアウトされていて画像が出力されない状態のようです)

ビューの移動の設定

デフォルトではマウスでのビューの移動は
「中ボタンドラッグが回転 Shift+中ボタンが平行移動」になっていて
監督がどうされているか分かる記述はないですが
2Dソフト的な使い方をメインにすることが多い場合 ショートカットの入れ替えをして
AfterEffects等のように中ボタンでの平行移動にしてしまった方がいいように思います
3Dビュー>3D View(Global)> ビューを回転 / ビューを移動 の項目になります

ドープシートにタイムラインウィンドウのUIを移植

頒布されている.blendファイルでは 操作の関係で多数のエディッタが表示状態になった状態になっていますが
UIを書き換えて必要なものだけに整理してしまうことはできないかなと感じました

Blenderのテキストエディッタをウィンドウ内のいずれかに表示した状態にして
GUIを右クリックして出るメニューの「ソース編集」を選択すると エディッタ上にGUIの配置等を記述した部分のPythonコードが表示され、これを編集することでGUIの並び等を変えることができるのですが
機能によっては他のエディッタの部品を移植することができます
細かい方法は別の記事にしますが、自分の環境ではドープシート画面にタイムラインのUIを一部移してあります

コンテ台紙への合成を自動化

本では描かれたグリースペンシル画像を.blendファイル内にあるスクリプト「blender_jump_keyframe_render_code_gl」を実行して
グリースペンシルのキーフレーム毎にOpenGLレンダリング出力するようになっています

本では書き出したコマ画像を並べて改めてレンダリングし直すことで
従来の紙で描いたコンテ用紙のフォーマットにされていますが、並べて合成する程度ならばスクリプトでやっればと作成してみました。
「blender_jump_keyframe_render_code_gl」の後半に追記することで動作するような仕組みにしてあります。
import numpy as np

#rgbaの画像をnumpy arrayに変換
def img_to_nparray(img):
    bit_len = len(img.pixels)
    (width,height) = img.size
    channels = img.channels #色数
    #numpy arrayを作成
    pixlist = np.array(img.pixels)
    pixlist = pixlist.reshape( height, width, 4)
    return( pixlist )

#画像の読み込み
def load_as_nparray(f_path):
    img = bpy.data.images.load(f_path)
    img_array = img_to_nparray(img)
    #読み込んだ画像オブジェクトの消去
    bpy.data.images.remove(img)
    return(img_array)


#numpy arrayをpng画像として保存
def save_nparray_png( save_path, img_name, np_array ):
    f_path = os.path.join( save_path, img_name )
    (height, width, deps) = np_array.shape
    #画像オブジェクトの作成
    img = bpy.data.images.new(name=img_name, width=width, height=height)
    img.pixels = list( np_array.flatten())
    #保存
    img.save_render(filepath=f_path)
    #画像オブジェクトの消去
    bpy.data.images.remove(img)
    

def combine_conteseet(output_path, name, frames):
    base_h_offset = 456 #コンテを並べる場所への縦オフセット
    base_end = 168 #コンテ台紙のフッタ部分の幅
    tile_height = 384 #コマの縦幅
    tile_offset = 30  #コマの横のオフセット
    #開いている.blendファイルのあるディレクトリを取得
    bl_path = bpy.data.filepath
    bl_directory = os.path.dirname(bl_path)
    render_path = bpy.path.abspath(output_path)
    #コンテ台紙の読み込み
    conte_base_path = os.path.join(bl_directory, "base", "conte_base_print_saize.png" )
    conte_array = load_as_nparray(conte_base_path )
    #情報の取得、調整(画像は左下が基準)
    (height_b, width_b, deps) = conte_array.shape
    tiles = (height_b -base_h_offset -base_end ) // tile_height
    base_h_offset = height_b -base_h_offset -tile_height
    count = len(frames)
    for i in range( (count -1)//tiles +1 ):
        #画像の初期化
        conte_array[base_end:base_h_offset +tile_height, 0: width_b] = np.array([1,1,1,1])
        #コマ画像を台紙上に並べて配置
        for j in range( min(tiles, count - i *tiles) ):
            #コマ画像の読み込み
            t = frames[ i*tiles +j ]
            fname = name+ str(t).zfill(4) + ".png"
            img_path = os.path.join(render_path, fname)
            cut_array = load_as_nparray(img_path)
            #合成する位置の設定
            h_offset = base_h_offset - tile_height * j
            (height, width, deps) = cut_array.shape
            #はみ出しはエラーになるため対策
            if width+tile_offset > width_b:
                width = width_b - tile_offset
                cut_array = cut_array[:,:width]
            #結合処理
            conte_array[h_offset : h_offset + height, tile_offset: width+tile_offset] = cut_array
        #numpy配列をPNG画像で保存
        img_name = 'conte_' + str(i).zfill(4) +".png"
        save_nparray_png( render_path, img_name, conte_array )
        
"""# テスト用データ
output_path = bpy.context.scene.render.filepath
name = "Camera"
frames = [8,40,41,95,99,100]
"""
combine_conteseet(output_path, name, frames)


画像を行列演算ライブラリのnumpyで合成しています。(普通に合成処理を書くよりだいぶ速い)
「blender_jump_keyframe_render_code_gl」で本体で使われていた 書き出し先、ファイル名に使う名前 書き出したキーフレームのリスト の変数を利用しています

今回のスクリプトは既存のものに追記する形ですが
bpy op のモジュールをインポートして多少の改変で他の画像を並べる処理にも使えるかと思います

以上独り善がりに書いてみましたが、
監督の本の内容の関連だけでなく何かしらのお役にたてれば幸いです