Last active
June 24, 2025 11:57
-
-
Save katapad/2a1f5b86dcfd2972f907548ed4eff167 to your computer and use it in GitHub Desktop.
import_alembic_from_browser.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import bpy | |
| import os | |
| import glob | |
| # 設定値(編集可能) | |
| TEXTURE_DIR_NAME = "texture" # テクスチャディレクトリ名 | |
| ALEMBIC_DIR_NAME = "alembic" # Alembicディレクトリ名 | |
| ALEMBIC_SCALE = 0.001 # Alembicインポート時のスケール | |
| FPS = 30 # フレームレート | |
| IMAGE_EXTENSION = "png" # 画像の拡張子("png" または "jpg") | |
| def import_alembic_with_texture(base_dir): | |
| """ | |
| Alembicファイルとテクスチャ連番画像をインポートする | |
| ディレクトリ構造: | |
| base_dir/ | |
| ├── texture/ (連番PNG画像) | |
| └── alembic/ (Alembicファイル) | |
| """ | |
| # 選択したディレクトリ名を取得 | |
| dir_name = os.path.basename(os.path.normpath(base_dir)) | |
| texture_dir = os.path.join(base_dir, TEXTURE_DIR_NAME) | |
| alembic_dir = os.path.join(base_dir, ALEMBIC_DIR_NAME) | |
| # ディレクトリの存在確認 | |
| if not os.path.exists(texture_dir): | |
| raise Exception(f"テクスチャディレクトリが見つかりません: {texture_dir}") | |
| if not os.path.exists(alembic_dir): | |
| print(f"警告: Alembicディレクトリが見つかりません: {alembic_dir}") | |
| # 1. 連番画像マテリアルの作成 | |
| print("連番画像マテリアルを作成中...") | |
| # 画像を取得(拡張子を設定値から取得) | |
| image_files = sorted([f for f in os.listdir(texture_dir) if f.lower().endswith(f'.{IMAGE_EXTENSION.lower()}')]) | |
| if not image_files: | |
| raise Exception(f"textureディレクトリに{IMAGE_EXTENSION.upper()}画像が見つかりません") | |
| num_frames = len(image_files) | |
| print(f"見つかった画像: {num_frames}枚 ({IMAGE_EXTENSION.upper()}形式)") | |
| # シーン設定の更新 | |
| scene = bpy.context.scene | |
| scene.render.fps = FPS | |
| scene.frame_start = 1 | |
| scene.frame_end = num_frames | |
| print(f"シーン設定: FPS={FPS}, フレーム範囲=1-{num_frames}") | |
| # マテリアル作成 | |
| mat = bpy.data.materials.new(name="AlembicTexture") | |
| mat.use_nodes = True | |
| nodes = mat.node_tree.nodes | |
| nodes.clear() | |
| # ノード作成 | |
| tex = nodes.new('ShaderNodeTexImage') | |
| brightness = nodes.new('ShaderNodeBrightContrast') | |
| curves = nodes.new('ShaderNodeRGBCurve') | |
| shader = nodes.new('ShaderNodeBsdfPrincipled') | |
| output = nodes.new('ShaderNodeOutputMaterial') | |
| # 位置設定 | |
| tex.location = (-600, 0) | |
| brightness.location = (-400, 0) | |
| curves.location = (-200, 0) | |
| shader.location = (0, 0) | |
| output.location = (300, 0) | |
| # Principled BSDFの設定 | |
| shader.inputs['Roughness'].default_value = 0.97 | |
| # 画像読み込み | |
| first_image = os.path.join(texture_dir, image_files[0]) | |
| img = bpy.data.images.load(first_image) | |
| img.source = 'SEQUENCE' | |
| # Image Sequenceの設定 | |
| tex.image = img | |
| tex.image_user.frame_duration = num_frames | |
| tex.image_user.frame_start = 0 | |
| tex.image_user.frame_offset = -1 | |
| tex.image_user.use_auto_refresh = True | |
| tex.image_user.use_cyclic = False | |
| # ノード接続 | |
| links = mat.node_tree.links | |
| links.new(tex.outputs['Color'], brightness.inputs['Color']) | |
| links.new(brightness.outputs['Color'], curves.inputs['Color']) | |
| links.new(curves.outputs['Color'], shader.inputs['Base Color']) | |
| links.new(shader.outputs['BSDF'], output.inputs['Surface']) | |
| print("マテリアル作成完了") | |
| # 2. Alembicファイルのインポート | |
| all_imported_objects = [] | |
| if os.path.exists(alembic_dir): | |
| # Alembicファイルを検索 | |
| abc_files = glob.glob(os.path.join(alembic_dir, "*.abc")) | |
| if abc_files: | |
| print(f"\nAlembicファイルをインポート中...") | |
| # 親となるEmptyオブジェクトを作成 | |
| bpy.ops.object.empty_add(type='PLAIN_AXES', location=(0, 0, 0)) | |
| parent_empty = bpy.context.active_object | |
| parent_empty.name = f"{dir_name}_Parent" | |
| parent_empty.empty_display_size = 0.0 | |
| for abc_file in abc_files: | |
| print(f"インポート: {os.path.basename(abc_file)}") | |
| # インポート前の既存オブジェクトを記録 | |
| existing_objects = set(bpy.data.objects) | |
| # Alembicインポート | |
| bpy.ops.wm.alembic_import( | |
| filepath=abc_file, | |
| scale=ALEMBIC_SCALE, | |
| set_frame_range=True, | |
| always_add_cache_reader=True | |
| ) | |
| # 新しくインポートされたオブジェクトを特定 | |
| new_objects = list(set(bpy.data.objects) - existing_objects) | |
| all_imported_objects.extend(new_objects) | |
| # インポートされたオブジェクトの処理 | |
| mesh_count = 0 | |
| for obj in new_objects: | |
| if obj.type == 'MESH': | |
| mesh_count += 1 | |
| # オブジェクト名をディレクトリ名に変更 | |
| if len(new_objects) == 1: | |
| obj.name = dir_name | |
| else: | |
| obj.name = f"{dir_name}_{mesh_count:03d}" | |
| # マテリアルを適用 | |
| if len(obj.data.materials) > 0: | |
| obj.data.materials[0] = mat | |
| else: | |
| obj.data.materials.append(mat) | |
| print(f" マテリアル適用: {obj.name}") | |
| # すべてのインポートが完了した後の処理 | |
| print("\nTransformの調整とApply処理...") | |
| # まず全選択を解除 | |
| bpy.ops.object.select_all(action='DESELECT') | |
| for obj in all_imported_objects: | |
| if obj.type == 'MESH': | |
| # オブジェクトを選択 | |
| obj.select_set(True) | |
| bpy.context.view_layer.objects.active = obj | |
| # Transform適用 | |
| bpy.ops.object.transform_apply(location=False, rotation=False, scale=True) | |
| # 親を設定 | |
| obj.parent = parent_empty | |
| # 選択解除 | |
| obj.select_set(False) | |
| print(f" Transform適用完了: {obj.name}") | |
| print("\nインポート完了!") | |
| else: | |
| print("Alembicファイルが見つかりませんでした") | |
| # テスト用にプレーンを作成 | |
| bpy.ops.mesh.primitive_plane_add(size=2) | |
| obj = bpy.context.active_object | |
| obj.name = dir_name + "_TestPlane" | |
| obj.data.materials.append(mat) | |
| print("テスト用のPlaneを作成しました") | |
| print(f"\n完了: テクスチャ{num_frames}枚、フレーム0から開始") | |
| class SelectDirectoryOperator(bpy.types.Operator): | |
| """ディレクトリを選択""" | |
| bl_idname = "select.directory" | |
| bl_label = "Select Directory" | |
| directory: bpy.props.StringProperty( | |
| name="Directory Path", | |
| description="Choose a directory", | |
| default="", | |
| subtype='DIR_PATH' | |
| ) | |
| def execute(self, context): | |
| print(f"選択されたディレクトリ: {self.directory}") | |
| try: | |
| # 選択されたディレクトリで import_alembic_with_texture を実行 | |
| import_alembic_with_texture(self.directory) | |
| self.report({'INFO'}, "インポートが完了しました!") | |
| return {'FINISHED'} | |
| except Exception as e: | |
| self.report({'ERROR'}, str(e)) | |
| return {'CANCELLED'} | |
| def invoke(self, context, event): | |
| # ファイルブラウザを開く | |
| context.window_manager.fileselect_add(self) | |
| return {'RUNNING_MODAL'} | |
| # スクリプト実行 | |
| if __name__ == "__main__": | |
| # オペレーターを登録 | |
| bpy.utils.register_class(SelectDirectoryOperator) | |
| # オペレーターを実行 | |
| bpy.ops.select.directory('INVOKE_DEFAULT') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment