見出し画像

Blender 基本シーン設定スクリプト


"""
タイトル: Blender 基本シーン設定スクリプト
説明:
Blenderでの基本的なシーン設定を効率化するスクリプト。
ステージクリア、カメラ・照明の設置、背景色の指定、プリミティブオブジェクトの配置、マテリアル生成などの機能を含む。
すべての処理を個別の関数に分割して再利用可能に設計されています。

作成日: 2024年11月18日
バージョン: 1.6.0


以下読み込み方書式
import sys
import os

# スクリプトのあるディレクトリをPythonパスに追加
script_dir = os.path.dirname(bpy.data.filepath)
if script_dir not in sys.path:
    sys.path.append(script_dir)

# インポート
from setup_stage import clear_stage,create_camera,create_light,set_background_color

"""

import bpy
import math
import mathutils

# ステージクリア(カメラ・照明を残すかどうかを引数で指定)
def clear_stage(keep_camera=True, keep_lights=True):
    for obj in bpy.data.objects:
        if (obj.type == 'CAMERA' and keep_camera) or (obj.type == 'LIGHT' and keep_lights):
            continue
        bpy.data.objects.remove(obj, do_unlink=True)

# シーン内のすべてのマテリアルを削除します。
def clear_materials():
    try:
        # マテリアルを削除
        for mat in bpy.data.materials:
            bpy.data.materials.remove(mat, do_unlink=True)
        print("すべてのマテリアルを削除しました。")
        return True
    except Exception as e:
        print(f"マテリアル削除中にエラーが発生しました: {e}")
        return False

# カメラを設置する関数
def create_camera(location=(0, 0, 10), rotation=(math.radians(90), 0, 0), name="Camera"):
    bpy.ops.object.camera_add(location=location)
    camera = bpy.context.object
    camera.name = name
    camera.rotation_euler = rotation
    return camera

#   指定したカメラを特定のオブジェクトまたは座標方向に向けます。
def point_camera(camera, target=None, target_location=None):
    """
    Args:
        camera (bpy.types.Object): カメラオブジェクト。
        target (bpy.types.Object): カメラが向く対象のオブジェクト(指定しない場合は target_location を使用)。
        target_location (tuple): カメラが向く座標 (x, y, z)。target が None の場合に有効。
    
    Returns:
        bool: 成功した場合は True、失敗した場合は False。
    """
    try:
        if target is not None:
            # 対象オブジェクトのワールド座標を取得
            target_location = target.matrix_world.translation
        elif target_location is None:
            raise ValueError("target または target_location のいずれかを指定する必要があります。")
        
        # カメラの位置を取得
        camera_location = camera.matrix_world.translation
        
        # カメラの方向ベクトルを計算
        direction = camera_location -mathutils.Vector(target_location)
        direction.normalize()
        
        # 回転マトリックスを計算
        rotation = direction.to_track_quat('Z', 'Y').to_euler()
        
        # カメラの回転を設定
        camera.rotation_euler = rotation
        return True
    except Exception as e:
        print(f"カメラの向き変更中にエラーが発生しました: {e}")
        return False

# 照明を設置する関数
def create_light(location=(10, 10, 10), rotation=(math.radians(0), math.radians(45), 0), light_type='SUN', energy=1000, color=(1.0, 1.0, 1.0), name="Light"):
    # 照明の種類 ('SUN', 'POINT', 'SPOT', 'AREA')
    bpy.ops.object.light_add(type=light_type, location=location)
    light = bpy.context.object
    light.name = name
    light.rotation_euler = rotation
    light.data.energy = energy
    light.data.color = color
    return light

# 照明をターゲットに向ける関数
def point_light(light_object, target_location):
    try:
        if light_object.type != 'LIGHT':
            raise ValueError(f"Object '{light_object.name}' is not a light.")
        light_location = mathutils.Vector(light_object.location)
        direction = mathutils.Vector(target_location) - light_location
        rotation = direction.to_track_quat('-Z', 'Y').to_euler()
        light_object.rotation_euler = rotation
        return True
    except Exception as e:
        print(f"照明の向き変更中にエラーが発生しました: {e}")
        return False

# 背景色を指定する関数(成功したかどうかを返す)
def set_background_color(color=(0.0, 0.0, 0.0, 1.0)):
    bpy.context.scene.world.use_nodes = True
    bg_node = bpy.context.scene.world.node_tree.nodes.get("Background")
    if bg_node:
        bg_node.inputs[0].default_value = color  # 色指定 (RGBA)
        return True
    else:
        print("背景ノードが見つかりません。スキップします。")
        return False

def initialize_stage(
    camera_location=(0, 10, 10),
    camera_rotation=(math.radians(45), math.radians(0), math.radians(180)),
    light_location=(5, 5, 5),
    light_rotation=(math.radians(-45), math.radians(0), 0),
    light_type='SUN',
    light_energy=5,
    light_color=(1.0, 1.0, 1.0),
    background_color=(0.0, 0.0, 0.5, 1.0),
    keep_camera=False,
    keep_lights=False,
    keep_matelials=True):
    
    clear_stage(keep_camera=keep_camera, keep_lights=keep_lights)
    if keep_matelials:
        clear_materials()
    camera = create_camera(location=camera_location, rotation=camera_rotation, name="Camera")
    light = create_light(location=light_location, rotation=light_rotation, light_type=light_type, color=light_color, energy=light_energy, name="Light")
    set_background_color(color=background_color)
    
    return camera,light

# マテリアルを生成する関数
def create_material(name="Material", color=(1.0, 1.0, 1.0, 1.0)):
    mat = bpy.data.materials.get(name)
    if not mat:
        mat = bpy.data.materials.new(name=name)
        mat.use_nodes = True
        bsdf = mat.node_tree.nodes.get("Principled BSDF")
        if bsdf:
            bsdf.inputs["Base Color"].default_value = color
    return mat

# プリミティブオブジェクトを配置する関数
def create_primitive_object(object_type='SPHERE', location=(0, 0, 0), scale=(1, 1, 1), rotation=(0, 0, 0), color=(1.0, 1.0, 1.0, 1.0), name="Object"):
    if object_type.upper() == 'SPHERE':
        bpy.ops.mesh.primitive_uv_sphere_add(location=location)
    elif object_type.upper() == 'CUBE':
        bpy.ops.mesh.primitive_cube_add(location=location)
    elif object_type.upper() == 'CYLINDER':
        bpy.ops.mesh.primitive_cylinder_add(location=location)
    elif object_type.upper() == 'CONE':
        bpy.ops.mesh.primitive_cone_add(location=location)
    elif object_type.upper() == 'PLANE':
        bpy.ops.mesh.primitive_plane_add(location=location)
    else:
        raise ValueError(f"Unsupported object type: {object_type}")

    obj = bpy.context.object
    obj.name = name
    obj.scale = scale
    obj.rotation_euler = rotation

    # マテリアルを設定
    mat = create_material(name=f"{name}_Material", color=color)
    obj.data.materials.append(mat)
    return obj

# メイン処理
if __name__ == "__main__":
    # 初期設定
    camera, light = initialize_stage(
        camera_location=(20, 10, 10),
        camera_rotation=(math.radians(90), 0, 0),
        light_location=(0, 10, 10),
        #light_type='SUN',  # 照明の種類 ('SUN', 'POINT', 'SPOT', 'AREA')
        light_type='SPOT',  # 照明の種類 ('SUN', 'POINT', 'SPOT', 'AREA')
        light_energy=5000,
        light_color=(1.0, 1.0, 0.3),
        background_color=(0.0, 0.3, 0.8, 1.0),  # 青い背景
        keep_camera=False,
        keep_lights=False,
        keep_matelials=True
    )

    # 座標に向ける
    target_location = (0, 0, 0)  # 原点に向ける
    point_camera(camera, target_location=(0, -1, 0))
    point_light(light, target_location)

    # 原点に配置
    create_primitive_object(object_type='PLANE', location=(0, 0, 0), scale=(25, 25, 25), rotation=(0, 0, 0), color=(0.5, 0.9, 0.5, 1.0), name="Plane")
    create_primitive_object(object_type='SPHERE', location=(-2, 0, 1.5), scale=(1, 1, 1), rotation=(0, 0, 0), color=(1.0, 0.0, 0.0, 1.0), name="RedSphere")
    create_primitive_object(object_type='CUBE', location=(2, 0, 1.5), scale=(1, 1, 1), rotation=(math.radians(45), math.radians(45), math.radians(45)), color=(0.0, 0.0, 1.0, 1.0), name="BlueCube")

いいなと思ったら応援しよう!