スクリーンショット_2019-08-18_08

オブジェクトのコマを抜く[.blend]

ついったにオブジェクトのコマ抜きのお話しが流れてきました。

背景はフルコマで動いて、主要なオブジェクトはコマを抜いてアニメーションする。
これは(題材として)面白そうね。


都度親子関係付けて、キーフレームベイクすればプレビューでいけんじゃね?っていうことで。

あっ、なんかできたっぽい。(めちゃめちゃ試行錯誤しましたけど)

コマ抜いた方。終わりの方のコマ、GIF最適化がうまくいってないですけどまあそれはご愛嬌。

POCコード

POC、出来るかどうか確認の為のコードですので本来必要なエラーハンドリングとか無いです。

m の値を適当に変えておいて、スクリプト実行、対象オブジェクトにコンストレイント設定するだけ。元の動きに戻すのもコンストレイント外すだけ。簡単。ページからダウンロードできる .blendファイルにも入れときました。

# (POC) skip frames 
# 
# 1. select target object , and camera 
# 2. run script
# 3. set constraints to target object (manually)
#     copy location -> new_obj
#     copy rotation -> new_obj
# 4. play animation
# 5. yaay!!
#

import bpy
import mathutils

m = 4

scene = bpy.context.scene
layer = bpy.context.view_layer
act_obj = bpy.context.object
sel_objs = bpy.context.selected_objects
src_obj = None

if act_obj.type == 'CAMERA':
   l = len(sel_objs)
   if l == 2:
       for x in sel_objs:
            if x != act_obj:
               src_obj = x

if src_obj != None:
   new_obj = bpy.data.objects.new('new_obj', None) 
   scene.collection.objects.link( new_obj )
   tmp_obj = bpy.data.objects.new('tmp_obj', None) 
   scene.collection.objects.link( tmp_obj )

c = 0
src_obj.select_set(False)
tmp_obj.select_set(True)

for x in range( scene.frame_start, scene.frame_end):
       scene.frame_set(x)        

       if (c % m ) == 0:
           if tmp_obj.parent != None:
               bpy.ops.object.parent_clear(type='CLEAR')
           tmp_obj.location = src_obj.location
           tmp_obj.rotation_euler = src_obj.rotation_euler
           bpy.ops.object.parent_set(type='OBJECT', keep_transform=False)

       layer.update()
       loc , rot, sca = tmp_obj.matrix_world.decompose()
       print(rot)
       new_obj.location = loc
       new_obj.rotation_euler = rot.to_euler()
       new_obj.keyframe_insert(data_path='location', frame=(x))
       new_obj.keyframe_insert(data_path='rotation_euler', frame=(x))

       c=c+1

scene.frame_set(1) 

.blendファイル

スクリプト実行前と後を置いておきます。それぞれのファイルを3Dビューでアニメーションプレビューしてみてください。

動画とAdd-onについて

@CodyWinch さんがAdd-onを公開していて、その動画見たんですけど、カメラに対するオブジェクトのちらつきは(1)Emptyを親にしておいてアニメーション付け、(2)Emptyに移動差分をカウンターとして相殺するアニメーションを付ける、っていう感じで実現しています。

対して上のスクリプトでは、別オブジェクト(Empty)にカメラを親とした時の動きをコマごとにキーを打つ、っていうやり方をしています。

フルコマ、4コマ、8コマ、16コマのサンプルです。

----

8/20版。カメラオブジェクトに親がいる場合を考慮

# (POC) skip frames 2019/08/20
# 
# 1. select target object , and camera 
# 2. run script
# 3. set constraints to target object (manually)
#     copy location -> new_obj
#     copy rotation -> new_obj
# 4. play animation
# 5. yaay!!
#

import bpy
import mathutils

m = 4

scene = bpy.context.scene
layer = bpy.context.view_layer
act_obj = bpy.context.object
sel_objs = bpy.context.selected_objects
src_obj = None

if act_obj.type == 'CAMERA':
   l = len(sel_objs)
   if l == 2:
       for x in sel_objs:
           if x != act_obj:
               src_obj = x

   if src_obj != None:
       new_obj = bpy.data.objects.new('new_obj', None) 
       scene.collection.objects.link( new_obj )
       tmp_obj = bpy.data.objects.new('tmp_obj', None) 
       scene.collection.objects.link( tmp_obj )

       c = 0
       src_obj.select_set(False)
       new_obj.select_set(False)
       tmp_obj.select_set(True)

       for x in range( scene.frame_start, scene.frame_end):
           scene.frame_set(x)        
           layer.update()

           if (c % m ) == 0:
               if tmp_obj.parent != None:
                   layer.objects.active = tmp_obj 
                   act_obj.select_set(False )
                   bpy.ops.object.parent_clear(type='CLEAR')

           tmp_obj.location = src_obj.location
           tmp_obj.rotation_euler = src_obj.rotation_euler
           layer.objects.active = act_obj
           act_obj.select_set(True )
           bpy.ops.object.parent_set(type='OBJECT', keep_transform=False)

           layer.update()
           loc , rot, sca = tmp_obj.matrix_world.decompose()

           new_obj.location = loc
           new_obj.rotation_euler = rot.to_euler()
           new_obj.keyframe_insert(data_path='location', frame=(x))
           new_obj.keyframe_insert(data_path='rotation_euler', frame=(x))

       c=c+1

scene.frame_set(1)

お読みいただきありがとうございます。サポートいただいた分はおやつのグレードアップに使おうかと思います。スキ、SNSにシェアもよろしくお願いします!