見出し画像

blenderのpython。距離でマテリアルカラーを変化させる関数

"""
タイトル: 距離による球体の色変化(比率指定版)
説明:
Blenderシーン内で原点に球体を生成し、ランダムに移動。
球体の色は、原点からの距離に応じて赤から青に変化、
距離と色の変化比率を指定できます。

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

import bpy
import random
import math

def create_material_with_color_ratio(name, color1, color2, ratio):
    """
    原点からの距離に応じて色を変化させるマテリアルを作成。
    Args:
        name (str): マテリアル名。
        color1 (tuple): 距離が小さいときの色 (R, G, B, A)。
        color2 (tuple): 距離が大きいときの色 (R, G, B, A)。
        ratio (float): 距離と色の変化の比率。
    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")
        bsdf_node = nodes.new(type="ShaderNodeBsdfPrincipled")
        distance_node = nodes.new(type="ShaderNodeVectorMath")
        scale_node = nodes.new(type="ShaderNodeMath")
        color_ramp_node = nodes.new(type="ShaderNodeValToRGB")
        geometry_node = nodes.new(type="ShaderNodeNewGeometry")

        # ノード設定
        distance_node.operation = 'LENGTH'
        scale_node.operation = 'MULTIPLY'
        scale_node.inputs[1].default_value = ratio  # 距離と色変化の比率

        color_ramp_node.color_ramp.interpolation = 'LINEAR'
        color_ramp_node.color_ramp.elements[0].color = color1  # 色1(近い)
        color_ramp_node.color_ramp.elements[1].color = color2  # 色2(遠い)

        # ノードを接続
        links.new(geometry_node.outputs["Position"], distance_node.inputs[0])
        links.new(distance_node.outputs["Value"], scale_node.inputs[0])  # 距離をスケーリング
        links.new(scale_node.outputs["Value"], color_ramp_node.inputs["Fac"])
        links.new(color_ramp_node.outputs["Color"], bsdf_node.inputs["Base Color"])
        links.new(bsdf_node.outputs["BSDF"], output_node.inputs["Surface"])

    return mat


def create_moving_sphere(location, material_name, color1, color2, ratio):
    """
    球体を作成し、指定したマテリアルを適用します。
    Args:
        location (tuple): 球体の初期位置。
        material_name (str): 使用するマテリアル名。
        color1 (tuple): 距離が小さいときの色。
        color2 (tuple): 距離が大きいときの色。
        ratio (float): 距離と色変化の比率。
    Returns:
        bpy.types.Object: 作成した球体。
    """
    bpy.ops.mesh.primitive_uv_sphere_add(radius=1, location=location)
    sphere = bpy.context.object
    bpy.ops.object.shade_smooth()
    mat = create_material_with_color_ratio(material_name, color1, color2, ratio)
    sphere.data.materials.append(mat)
    return sphere


def animate_sphere_movement(sphere, frame_start, frame_end, frame_interval, move_range):
    """
    球体のランダムな動きをアニメーション化します。
    Args:
        sphere (bpy.types.Object): アニメーション化する球体。
        frame_start (int): アニメーションの開始フレーム。
        frame_end (int): アニメーションの終了フレーム。
        frame_interval (int): フレーム間隔。
        move_range (tuple): 移動範囲 (min, max)。
    """
    for frame in range(frame_start, frame_end + 1, frame_interval):
        bpy.context.scene.frame_set(frame)

        # ランダムな新しい位置を計算
        new_location = (
            random.uniform(*move_range),
            random.uniform(*move_range),
            random.uniform(*move_range)
        )

        # 球体の位置を更新
        sphere.location = new_location
        sphere.keyframe_insert(data_path="location", frame=frame)


def main():
    # 既存のオブジェクトとマテリアルを削除
    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)

    # 球体を作成
    sphere = create_moving_sphere(
        location=(0, 0, 0),
        material_name="DistanceColorMaterial",
        color1=(1.0, 0.0, 0.0, 1.0),  # 赤
        color2=(0.0, 0.0, 1.0, 1.0),  # 青
        ratio=0.2  # 色変化の比率(小さいほど敏感に変化)
    )

    # アニメーションの設定
    frame_start = 1
    frame_end = 250
    frame_interval = 10
    move_range = (-5, 5)  # 移動範囲

    # 球体の動きをアニメーション化
    animate_sphere_movement(sphere, frame_start, frame_end, frame_interval, move_range)

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


# スクリプトの実行
main()

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