見出し画像

Diffuse BSDFの「Color」入力をRGBそれぞれの比率でコントロール

"""
タイトル: RGB比率コントロール可能なマテリアルアニメーションスクリプト(Combine XYZ 使用版)
説明:
Diffuse BSDFの「Color」入力にCombine XYZノードを接続し、ValueノードでRGBそれぞれの比率をコントロールします。
アニメーションで色比率を動的に変更することが可能です。

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

import bpy


def setup_scene():
    """カメラとライト、既存のオブジェクトを初期化"""
    # 既存のオブジェクトを削除
    for obj in bpy.data.objects:
        bpy.data.objects.remove(obj, do_unlink=True)

    # 既存のマテリアルを削除
    for mat in bpy.data.materials:
        bpy.data.materials.remove(mat, do_unlink=True)

    # カメラを追加
    bpy.ops.object.camera_add(location=(0, -10, 5), rotation=(1.1, 0, 0))
    camera = bpy.context.object
    camera.name = "Camera"

    # ライトを追加
    bpy.ops.object.light_add(type='POINT', location=(5, -5, 10))
    light = bpy.context.object
    light.name = "Light"


def create_rgb_material_with_combine(name):
    """
    Combine XYZを使用してRGB比率をコントロールするマテリアルを作成。

    Args:
        name (str): マテリアル名。

    Returns:
        bpy.types.Material: 作成したマテリアル。
    """
    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
        links = mat.node_tree.links

        # ノードのクリア
        for node in nodes:
            nodes.remove(node)

        # 必要なノードを追加
        output_node = nodes.new(type="ShaderNodeOutputMaterial")
        diffuse_node = nodes.new(type="ShaderNodeBsdfDiffuse")
        combine_xyz = nodes.new(type="ShaderNodeCombineXYZ")
        value_r = nodes.new(type="ShaderNodeValue")
        value_g = nodes.new(type="ShaderNodeValue")
        value_b = nodes.new(type="ShaderNodeValue")

        # Valueノードの初期値(RGBの比率)
        value_r.outputs[0].default_value = 1.0  # 赤
        value_g.outputs[0].default_value = 0.0  # 緑
        value_b.outputs[0].default_value = 0.0  # 青

        # ノードを接続
        links.new(value_r.outputs[0], combine_xyz.inputs[0])  # R
        links.new(value_g.outputs[0], combine_xyz.inputs[1])  # G
        links.new(value_b.outputs[0], combine_xyz.inputs[2])  # B
        links.new(combine_xyz.outputs[0], diffuse_node.inputs["Color"])
        links.new(diffuse_node.outputs["BSDF"], output_node.inputs["Surface"])

        # Valueノードをマテリアルプロパティとして保存
        mat["value_nodes"] = {
            "R": value_r.name,
            "G": value_g.name,
            "B": value_b.name,
        }

    return mat


def animate_rgb_material(mat, frame_start, frame_interval, color_sequence):
    """
    マテリアルのRGB比率をアニメーション化します。

    Args:
        mat (bpy.types.Material): マテリアル。
        frame_start (int): アニメーション開始フレーム。
        frame_interval (int): 各切り替え間隔のフレーム数。
        color_sequence (list): 色の比率のリスト [(R, G, B), ...]。
    """
    value_nodes = mat.get("value_nodes")
    if not value_nodes:
        print("Value nodes not found in material.")
        return

    value_r = mat.node_tree.nodes.get(value_nodes["R"])
    value_g = mat.node_tree.nodes.get(value_nodes["G"])
    value_b = mat.node_tree.nodes.get(value_nodes["B"])

    if not value_r or not value_g or not value_b:
        print("Value nodes not found in material nodes.")
        return

    frame = frame_start
    for color_ratio in color_sequence:
        r, g, b = color_ratio

        # 計算された比率を設定
        value_r.outputs[0].default_value = r
        value_g.outputs[0].default_value = g
        value_b.outputs[0].default_value = b

        # アニメーションキーを挿入
        value_r.outputs[0].keyframe_insert(data_path="default_value", frame=frame)
        value_g.outputs[0].keyframe_insert(data_path="default_value", frame=frame)
        value_b.outputs[0].keyframe_insert(data_path="default_value", frame=frame)

        # 次のフレームに進む
        frame += frame_interval


def main():
    # シーンのセットアップ
    setup_scene()

    # 球体を作成
    bpy.ops.mesh.primitive_uv_sphere_add(radius=1, location=(0, 0, 1))
    sphere = bpy.context.object
    bpy.ops.object.shade_smooth()
    sphere.name = "Sphere"

    # マテリアルを作成して球体に適用
    rgb_material = create_rgb_material_with_combine("RGBMaterial")
    sphere.data.materials.append(rgb_material)

    # アニメーション設定
    frame_start = 1
    frame_interval = 30
    color_sequence = [
        (1.0, 0.0, 0.0),  # 赤
        (0.0, 1.0, 0.0),  # 緑
        (0.0, 0.0, 1.0),  # 青
        (1.0, 1.0, 0.0),  # 黄色(赤と緑の混合)
        (0.0, 1.0, 1.0),  # シアン(緑と青の混合)
        (1.0, 0.0, 1.0)   # マゼンタ(赤と青の混合)
    ]
    animate_rgb_material(rgb_material, frame_start, frame_interval, color_sequence)

    # 初期フレームを設定
    bpy.context.scene.frame_set(1)


# 実行
main()

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