見出し画像

blenderのPrincipled BSDFの各設定をpythonでランダムに変化させる関数

"""
タイトル: プリンシプルBSDFマテリアルプロパティのランダムアニメーションスクリプト
説明:
このスクリプトはBlender内のオブジェクトに適用されるプリンシプルBSDFマテリアルの
すべての主要プロパティをランダムにアニメーション化します。
色、メタリック、ラフネス、トランスミッションなどのプロパティが、
指定したフレーム間隔と範囲内で変化します。

作成日時: 2024年11月17日
バージョン: 1.1.0
"""

import bpy
import random


def create_fully_controllable_material(
    name, base_color=(1.0, 1.0, 1.0, 1.0), metallic=0.0, roughness=0.5, ior=1.45, alpha=1.0,
    transmission=0.0, subsurface=0.0, specular_ior=0.5, specular_tint=(1.0, 1.0, 1.0, 1.0),
    anisotropic=0.0, anisotropic_rotation=0.0, coat_weight=0.0, coat_roughness=0.03, coat_ior=1.5,
    sheen_weight=0.0, sheen_roughness=0.5, emission_color=(0.0, 0.0, 0.0, 1.0), emission_strength=0.0,
    normal_map=None
):
    """
    任意のプロパティを設定可能なプリンシプルBSDFマテリアルを作成します。
    """
    mat = bpy.data.materials.get(name)
    if mat is None:
        mat = bpy.data.materials.new(name=name)
        mat.use_nodes = True
        nodes = mat.node_tree.nodes
        bsdf_node = nodes.get("Principled BSDF")
        
        if bsdf_node:
            # プロパティを設定
            bsdf_node.inputs["Base Color"].default_value = base_color
            bsdf_node.inputs["Metallic"].default_value = metallic
            bsdf_node.inputs["Roughness"].default_value = roughness
            bsdf_node.inputs["IOR"].default_value = ior
            bsdf_node.inputs["Alpha"].default_value = alpha
            
            # Transmission の存在を確認して設定
            if "Transmission" in bsdf_node.inputs:
                bsdf_node.inputs["Transmission"].default_value = transmission
            
            if "Subsurface" in bsdf_node.inputs:
                bsdf_node.inputs["Subsurface"].default_value = subsurface
            
            if "IOR Level" in bsdf_node.inputs:
                bsdf_node.inputs["IOR Level"].default_value = specular_ior
            
            if "Tint" in bsdf_node.inputs:
                bsdf_node.inputs["Tint"].default_value = specular_tint
            
            if "Anisotropic" in bsdf_node.inputs:
                bsdf_node.inputs["Anisotropic"].default_value = anisotropic
            
            if "Anisotropic Rotation" in bsdf_node.inputs:
                bsdf_node.inputs["Anisotropic Rotation"].default_value = anisotropic_rotation
            
            if "Coat" in bsdf_node.inputs:
                bsdf_node.inputs["Coat"].default_value = coat_weight
            
            if "Coat Roughness" in bsdf_node.inputs:
                bsdf_node.inputs["Coat Roughness"].default_value = coat_roughness
            
            if "Coat IOR" in bsdf_node.inputs:
                bsdf_node.inputs["Coat IOR"].default_value = coat_ior
            
            if "Sheen" in bsdf_node.inputs:
                bsdf_node.inputs["Sheen"].default_value = sheen_weight
            
            if "Sheen Roughness" in bsdf_node.inputs:
                bsdf_node.inputs["Sheen Roughness"].default_value = sheen_roughness
            
            if "Emission Color" in bsdf_node.inputs:
                bsdf_node.inputs["Emission Color"].default_value = emission_color
            
            if "Emission Strength" in bsdf_node.inputs:
                bsdf_node.inputs["Emission Strength"].default_value = emission_strength
            
            if normal_map and "Normal" in bsdf_node.inputs:
                bsdf_node.inputs["Normal"].default_value = normal_map
    return mat



def animate_material_properties(
    mat, frame_start, frame_end, frame_interval,
    base_color_range=((0, 1), (0, 1), (0, 1), (1, 1)),
    metallic_range=(0.0, 1.0),
    roughness_range=(0.0, 1.0),
    transmission_range=(0.0, 1.0),
    ior_range=(1.0, 2.0),
    alpha_range=(0.0, 1.0),
    subsurface_range=(0.0, 1.0),
    specular_ior_range=(0.0, 1.0),
    anisotropic_range=(0.0, 1.0),
    anisotropic_rotation_range=(0.0, 1.0),
    coat_weight_range=(0.0, 1.0),
    coat_roughness_range=(0.0, 1.0),
    sheen_weight_range=(0.0, 1.0),
    sheen_roughness_range=(0.0, 1.0),
    emission_strength_range=(0.0, 10.0)
):
    """
    マテリアルの各プロパティをランダムにアニメーション化します。
    
    Args:
        mat (bpy.types.Material): アニメーション対象のマテリアル。
        frame_start (int): アニメーション開始フレーム。
        frame_end (int): アニメーション終了フレーム。
        frame_interval (int): プロパティ変更の間隔。
        各プロパティの*_range (tuple): 値の範囲 (min, max)。
    """
    nodes = mat.node_tree.nodes
    bsdf_node = nodes.get("Principled BSDF")
    if not bsdf_node:
        print("Error: 'Principled BSDF' node not found in the material.")
        return

    for frame in range(frame_start, frame_end + 1, frame_interval):
        # ランダムな値を生成し、それぞれのプロパティに設定
        base_color = (
            random.uniform(*base_color_range[0]),
            random.uniform(*base_color_range[1]),
            random.uniform(*base_color_range[2]),
            random.uniform(*base_color_range[3])
        )
        metallic = random.uniform(*metallic_range)
        roughness = random.uniform(*roughness_range)
        transmission = random.uniform(*transmission_range)
        ior = random.uniform(*ior_range)
        alpha = random.uniform(*alpha_range)
        subsurface = random.uniform(*subsurface_range)
        specular_ior = random.uniform(*specular_ior_range)
        anisotropic = random.uniform(*anisotropic_range)
        anisotropic_rotation = random.uniform(*anisotropic_rotation_range)
        coat_weight = random.uniform(*coat_weight_range)
        coat_roughness = random.uniform(*coat_roughness_range)
        sheen_weight = random.uniform(*sheen_weight_range)
        sheen_roughness = random.uniform(*sheen_roughness_range)
        emission_strength = random.uniform(*emission_strength_range)

        # アニメーションキーを挿入
        bsdf_node.inputs["Base Color"].default_value = base_color
        bsdf_node.inputs["Base Color"].keyframe_insert(data_path="default_value", frame=frame)

        bsdf_node.inputs["Metallic"].default_value = metallic
        bsdf_node.inputs["Metallic"].keyframe_insert(data_path="default_value", frame=frame)

        bsdf_node.inputs["Roughness"].default_value = roughness
        bsdf_node.inputs["Roughness"].keyframe_insert(data_path="default_value", frame=frame)

        if "Transmission" in bsdf_node.inputs:
            bsdf_node.inputs["Transmission"].default_value = transmission
            bsdf_node.inputs["Transmission"].keyframe_insert(data_path="default_value", frame=frame)

        bsdf_node.inputs["IOR"].default_value = ior
        bsdf_node.inputs["IOR"].keyframe_insert(data_path="default_value", frame=frame)

        bsdf_node.inputs["Alpha"].default_value = alpha
        bsdf_node.inputs["Alpha"].keyframe_insert(data_path="default_value", frame=frame)

        if "Subsurface" in bsdf_node.inputs:
            bsdf_node.inputs["Subsurface"].default_value = subsurface
            bsdf_node.inputs["Subsurface"].keyframe_insert(data_path="default_value", frame=frame)

        if "IOR Level" in bsdf_node.inputs:
            bsdf_node.inputs["IOR Level"].default_value = specular_ior
            bsdf_node.inputs["IOR Level"].keyframe_insert(data_path="default_value", frame=frame)

        if "Anisotropic" in bsdf_node.inputs:
            bsdf_node.inputs["Anisotropic"].default_value = anisotropic
            bsdf_node.inputs["Anisotropic"].keyframe_insert(data_path="default_value", frame=frame)

        if "Anisotropic Rotation" in bsdf_node.inputs:
            bsdf_node.inputs["Anisotropic Rotation"].default_value = anisotropic_rotation
            bsdf_node.inputs["Anisotropic Rotation"].keyframe_insert(data_path="default_value", frame=frame)

        if "Coat" in bsdf_node.inputs:
            bsdf_node.inputs["Coat"].default_value = coat_weight
            bsdf_node.inputs["Coat"].keyframe_insert(data_path="default_value", frame=frame)

        if "Coat Roughness" in bsdf_node.inputs:
            bsdf_node.inputs["Coat Roughness"].default_value = coat_roughness
            bsdf_node.inputs["Coat Roughness"].keyframe_insert(data_path="default_value", frame=frame)

        if "Sheen" in bsdf_node.inputs:
            bsdf_node.inputs["Sheen"].default_value = sheen_weight
            bsdf_node.inputs["Sheen"].keyframe_insert(data_path="default_value", frame=frame)

        if "Sheen Roughness" in bsdf_node.inputs:
            bsdf_node.inputs["Sheen Roughness"].default_value = sheen_roughness
            bsdf_node.inputs["Sheen Roughness"].keyframe_insert(data_path="default_value", frame=frame)

        if "Emission Strength" in bsdf_node.inputs:
            bsdf_node.inputs["Emission Strength"].default_value = emission_strength
            bsdf_node.inputs["Emission Strength"].keyframe_insert(data_path="default_value", frame=frame)


# Example usage
def main():
    # Remove all objects and materials
    bpy.ops.object.select_all(action='SELECT')
    bpy.ops.object.delete(use_global=False)
    for mat in bpy.data.materials:
        bpy.data.materials.remove(mat, do_unlink=True)

    # Add a sphere
    bpy.ops.mesh.primitive_uv_sphere_add(radius=1, location=(0, 0, 1))
    sphere = bpy.context.object
    bpy.ops.object.shade_smooth()

    # Create a material and apply it
    mat = create_fully_controllable_material(
        name="AnimatedMaterial",
        base_color=(1, 0, 0, 1),
        metallic=0.5,
        roughness=0.5
    )
    sphere.data.materials.append(mat)

    # Animate material properties
    animate_material_properties(
        mat, frame_start=1, frame_end=250, frame_interval=30,
        base_color_range=((0, 1), (0, 1), (0, 1), (1, 1)),
        metallic_range=(0.0, 1.0),
        roughness_range=(0.0, 1.0),
        transmission_range=(0.0, 1.0),
        ior_range=(1.0, 2.0),
        alpha_range=(0.0, 1.0),
        subsurface_range=(0.0, 1.0),
        specular_ior_range=(0.0, 1.0),
        anisotropic_range=(0.0, 1.0),
        anisotropic_rotation_range=(0.0, 1.0),
        coat_weight_range=(0.0, 1.0),
        coat_roughness_range=(0.0, 1.0),
        sheen_weight_range=(0.0, 1.0),
        sheen_roughness_range=(0.0, 1.0),
        emission_strength_range=(0.0, 5.0)
    )

# Execute the script
main()

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