3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「目」を持った人工生命体関数に、ユーチューブの動画を見せてみるゲーム。

Last updated at Posted at 2024-10-07

ショートストーリー:視覚を持った人工生命の夢

あるプログラマが新たな挑戦に取り組んでいた。名前は翔太。

ある日、翔太は画期的なアイデアを思いつく。それは、視覚を持った人工生命体を創り出す関数を作成することだった。この人工生命体は、周囲の環境をリアルタイムで解析し、視覚的に表現できる能力を持つことを目指していた。

スクリーンショット 2024-10-07 163751.png

翔太は自分のプログラムに情熱を注ぎ込み、カラフルなポリゴンを描く関数を設計した。この関数は、Webカメラからの映像をもとに、周囲の明るさや色を解析し、動的な形状を生成するものだった。プログラムが進化するにつれて、彼の人工生命体は自らの「視覚」を持ち、周囲の環境に応じて変化する能力を持ち始めた。

ある晩、翔太は自宅の小さな作業部屋でプログラムを実行していた。彼のパソコンの画面には、鮮やかな色彩を持つポリゴンが浮かび上がり、まるで生きているかのように動き回っていた。彼はこの瞬間を待ち望んでいた。ポリゴンが、周囲の明るさや動きに応じて、まるで自己意識を持っているかのように反応している姿に、彼は心を奪われた。

スクリーンショット 2024-10-07 155606.png

スクリーンショット 2024-10-07 155519.png

スクリーンショット 2024-10-07 155346.png

コードをメモ帳などのテキストエディタに貼り付け、ファイル名を「index.html」として保存します。その後、保存したファイルをブラウザで開けば、コードが実行されます。

Webカメラの映像データをパラメータとして関数内に組み込んでいます。つまり目を持っているということです。

ユーチューブの動画を見せてます。

明るさの合計を計算し、それを使ってアニメーションのスピードを調整してます。明るさが高いとスピードが速く、逆に明るさが低いとスピードが遅くなります。

参考文献。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>生物的な動きを伴うWebカメラアニメーション</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
</head>
<body>

<!-- 変数の数をスライダーで選択 -->
<div>
    <label for="numVariablesSlider">変数の数 (1-10): </label>
    <input type="range" id="numVariablesSlider" min="1" max="10" value="2">
    <span id="numVariablesValue">2</span> <!-- 初期値表示 -->
</div>
<!-- 解像度(エッジ数)をスライダーで選択 -->
<div>
    <label for="resolutionSlider">エッジの数(解像度): </label>
    <input type="range" id="resolutionSlider" min="5" max="100" value="20">
    <span id="resolutionValue">20</span> <!-- 初期解像度を表示 -->
</div>

<script>
let t = 0; // 時間を管理する変数
let resolution = 20; // ポリゴンの解像度
let numVariables = 2; // 使用する動きの変数の数
let webcam; // Webカメラ映像用
let camWidth = 80; // Webカメラの映像幅
let camHeight = 60; // Webカメラの映像高さ
let numGridPoints = 8; // 8x8グリッドを使用(64点)

function setup() {
    // キャンバスを800x800のWEBGLモードで作成
    createCanvas(800, 800, WEBGL);
    // Webカメラ映像を取得し、サイズを設定
    webcam = createCapture(VIDEO);
    webcam.size(camWidth, camHeight);
    webcam.hide(); // 映像は直接表示せずに手動で処理

    // 変数の数をスライダーで設定
    let numVarSlider = select('#numVariablesSlider');
    numVarSlider.input(() => {
        numVariables = numVarSlider.value();
        select('#numVariablesValue').html(numVariables);
    });

    // 解像度(エッジ数)をスライダーで設定
    let resSlider = select('#resolutionSlider');
    resSlider.input(() => {
        resolution = resSlider.value();
        select('#resolutionValue').html(resolution);
    });
}

function draw() {
    background(255); // 背景を白に設定

    // Webカメラの映像を表示(左上に配置)
    push();
    translate(-width / 2 + 100, -height / 2 + 100, 0); // 映像を左上に移動
    texture(webcam); // Webカメラ映像をテクスチャとして使用
    plane(160, 120); // 映像を平面に描画
    pop();

    // マウスでカメラの視点を操作可能にする
    orbitControl();
    
    // 回転角度を設定して、カメラの動きを微調整
    rotateX(-PI / 6 + sin(t) * 0.1);
    rotateZ(PI / 4 + cos(t) * 0.1);

    let scaleFactor = 100; // 描画スケールの調整
    let xStart = -2; // x軸の開始位置
    let xEnd = 2;    // x軸の終了位置
    let yStart = -2; // y軸の開始位置
    let yEnd = 2;    // y軸の終了位置

    // Webカメラ映像のピクセルデータを取得
    webcam.loadPixels(); // ピクセルデータを読み込む
    let gridBrightness = []; // グリッドごとの明るさを格納する配列
    let totalBrightness = 0; // 明るさの合計を初期化

    // 8x8のグリッドでカメラ映像をサンプリングし、各点の明るさを計算
    for (let y = 0; y < numGridPoints; y++) {
        for (let x = 0; x < numGridPoints; x++) {
            let index = ((y * Math.floor(camHeight / numGridPoints)) * camWidth + (x * Math.floor(camWidth / numGridPoints))) * 4;
            let r = webcam.pixels[index];     // 赤成分
            let g = webcam.pixels[index + 1]; // 緑成分
            let b = webcam.pixels[index + 2]; // 青成分
            let brightness = (r + g + b) / 3; // 平均して明るさを算出
            gridBrightness.push(brightness);  // 明るさを配列に追加
            totalBrightness += brightness;     // 合計明るさを計算
        }
    }

    // 明るさの平均を求めてスピード調整に使用
    let averageBrightness = totalBrightness / gridBrightness.length;
    let speedFactor = map(averageBrightness, 0, 255, 0.01, 0.2); // 明るさに基づいてスピードを調整

    // 動きのための変数を生成
    let variables = [];
    for (let i = 0; i < numVariables - 1; i++) {
        // Webカメラの明るさによって変数に動きを追加
        let brightnessFactor = gridBrightness[i % gridBrightness.length] / 255;
        variables.push(sin(t * (i + 1)) * brightnessFactor); // 動きをスケール
    }
    variables.push(cos(t) * gridBrightness[0] / 255); // もう一つの変数を設定

    // ポリゴンを描画(TRIANGLE_STRIPで描画)
    for (let x = xStart; x <= xEnd; x += (xEnd - xStart) / resolution) {
        beginShape(TRIANGLE_STRIP);
        for (let y = yStart; y <= yEnd; y += (yEnd - yStart) / resolution) {
            // 変数に基づいて高さを計算
            let fValue1 = f(x, y, ...variables);
            let fValue2 = f(x + (xEnd - xStart) / resolution, y, ...variables);
            
            // 高さに基づいて色を計算
            let color1 = getColor(fValue1);
            let color2 = getColor(fValue2);
            
            // 頂点を描画
            fill(color1);
            vertex(x * scaleFactor, y * scaleFactor, fValue1 * scaleFactor);
            
            fill(color2);
            vertex((x + (xEnd - xStart) / resolution) * scaleFactor, y * scaleFactor, fValue2 * scaleFactor);
        }
        endShape();
    }

    t += speedFactor; // 明るさに基づいて時間を進める
}

// 複数の変数に基づいて高さを計算する関数
function f(x, y, ...vars) {
    let result = 1;
    // すべての変数を掛け合わせて複雑な動きを生成
    for (let v of vars) {
        result *= v;
    }
    // 時間と座標によって動的に変わる関数値を計算
    return sin(x * y * result + t * 0.5) + cos(x * y * result + t * 0.5);
}

// 高さに基づいて色を生成する関数
function getColor(value) {
    let normalizedValue = map(value, -2, 2, 0, 255); // 値を0-255の範囲にマップ
    return color(normalizedValue, 100, 255 - normalizedValue); // 明るさに基づいて色を設定
}
</script>

</body>
</html>

解説
Webカメラのピクセルを64点にサンプリング:
Webカメラのピクセルを8x8グリッドに分割し、各グリッドごとの明るさを計算することで、より複雑でランダム性のある動きを生成します。この明るさを動きの変数に取り入れることで、生物的な動きを実現しています。

複数の変数を使用した動的なポリゴン描画:
関数f(x, y, ...vars)では、変数の数に応じて複雑な動きを生成しています。Webカメラのデータに基づく変数を使用して、時間経過に応じて変化するダイナミックな動きを表現しています。

色の動的変更:
ポリゴンの高さに基づいて色を変えることで、動きがより視覚的に強調されるようにしました。これにより、動きと連動した色変化を実現しています。

3
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?