プログラミングの備忘録

プログラムをつくる過程を残すもの

processingの備忘録 -AR 第2回-

こんにちは。
今回は「processingでAR」の第2回です。


前回、processingでARを扱えるようにするとともに、おまけとしてobjファイルを読み込んで表示する方法や、ARマーカーを複数使う・自作する方法を書いてみました。

taq.hatenadiary.jp

前回の最後にも書いたとおり、モデルが動いたり表示したモデルと何かしらインタラクションができたりすると面白そうです。

ということで、今回はそれをやってみます。


目次


モデルを動かす

備え付けの関数を使う

座標を変化させたり、rotate()を使ったりで並進、回転をさせることができます。

例えば、以下のコードではマーカーの位置に回転しながら浮く青い箱が表示されます。

import processing.video.*;
import jp.nyatla.nyar4psg.*;

Capture cam;
String[] cameras = Capture.list();
MultiMarker marker;
float c;

void setup(){
    size(640, 480, P3D);
    
    for(int i = 0; i < cameras.length; i ++){
        println("[" + i + "] " + cameras[i]);
    }

    cam = new Capture(this, cameras[1]);
    cam.start();
    
    marker = new MultiMarker(this, width, height, "../data/camera_para.dat", NyAR4PsgConfig.CONFIG_PSG);
    marker.addARMarker("../data/patt.hiro", 80);
}

void draw(){
    if(cam.available() == false){
        return;
    }
    cam.read();
    marker.detect(cam);
    marker.drawBackground(cam);
    
    if(marker.isExist(0) == true){
        marker.beginTransform(0);
        fill(0, 0, 255);
        translate(0, 0, 40);
        rotateX(c/100); //回転
        rotateY(c/100); //回転
        box(40);
        marker.endTransform();
    }
    
    c ++; //回転の角度を増やしていく
}


モーションデータを使う

モーションデータの中で「BVHファイル」というものがあります。
「BVH」は「Biovision Hierarchy」の略で、モーションキャプチャー用のデータが入ったファイルのようです。

以下のサイトの「example-processing」にあるファイルをダウンロードすると、processingで動かせるサンプルが入っています。

github.com

bvhファイルはデフォルトのprocessingでは開けませんが、上記のファイルにライブラリも入っており、開けるようになっています。

「p5f_sample.pde」を実行すると、準備体操をしているような人の動きが点で表現されたものが表示されます。


ではこれをARで表示できるようにしてみます。

import processing.video.*;
import jp.nyatla.nyar4psg.*;

Capture cam;
String[] cameras = Capture.list();
MultiMarker marker;

BvhParser parser = new BvhParser(); //無くても動くが、一応書いておく
PBvh bvh1, bvh2, bvh3; //読み込んだデータを入れておくところ

void setup(){
    size(640, 480, P3D);
    noStroke();
    
    for(int i = 0; i < cameras.length; i ++){
        println("[" + i + "] " + cameras[i]);
    }

    cam = new Capture(this, cameras[1]);
    cam.start();
    
    marker = new MultiMarker(this, width, height, "ar/camera_para.dat", NyAR4PsgConfig.CONFIG_PSG);
    marker.addARMarker("ar/patt.hiro", 80);
    
    //bvhファイルの読み込み
    bvh1 = new PBvh(loadStrings("motion/A_test.bvh"));
    bvh2 = new PBvh(loadStrings("motion/B_test.bvh"));
    bvh3 = new PBvh(loadStrings("motion/C_test.bvh"));
}

void draw(){
    if(cam.available() == false){
        return;
    }
    cam.read();
    marker.detect(cam);
    marker.drawBackground(cam);
    
    if(marker.isExist(0) == true){
        marker.beginTransform(0);
        scale(0.3);
        rotateX(PI/2);

        //次の動きに更新
        bvh1.update(millis());
        bvh2.update(millis());
        bvh3.update(millis());

        //表示
        bvh1.draw();
        bvh2.draw();
        bvh3.draw();

        marker.endTransform();
    }
}


先程ダウンロードしたファイルの「p5f_sample.pde」を上記のコードに変え、ARのデータも同じフォルダに入れて実行すると、

静止画だとわかりづらいかもしれませんが、人が3人動いてます。


この動きをobjと関連付けられれば人型の3Dモデルも動かすことができそうですが、それは今後の課題としたいと思います。


参考


おまけ

モーションデータとモデルの関連付けは今後の課題としましたが、現段階でもゴリ押しではありますがモデルを動せるので試してみました。


動画は静止画を高速で切り替えているものだとすると、モデルを動かしたければその動きをコマ送りでデータ化して連続的に表示させれば動いているように見せることができます。

ということで、前回取り込んだはちゅねミクがネギを振るアニメーションをARで表示できるようにしてみます。


まずは、Blenderを使ってobjファイルをつくっていきます。

はちゅねミクであれば、「Hachune_arm」を選んでボーンを可視化させ、ボーンを選択して左上で「Object Mode」から「Pose Mode」に変更します。
するとボーンの編集画面になるので、動かしたいところを動かして、objファイルで出力します。
とりあえず手の角度が違う4つのobjファイルをつくってみました。


続いて、つくったobjファイルを連続的に表示できるようにコードを変えます。

import processing.video.*;
import jp.nyatla.nyar4psg.*;

Capture cam;
String[] cameras = Capture.list();
MultiMarker marker;
PShape[] obj = new PShape[4]; //読み込むデータの長さの配列をつくる

void setup(){
    size(640, 480, P3D);
    
    for(int i = 0; i < cameras.length; i ++){
        println("[" + i + "] " + cameras[i]);
    }

    cam = new Capture(this, cameras[1]);
    cam.start();
    
    marker = new MultiMarker(this, width, height, "data/NyARToolkit/camera_para.dat", NyAR4PsgConfig.CONFIG_PSG);
    marker.addARMarker("data/NyARToolkit/patt.hiro", 80);

    //objファイルの読み込み
    obj[0] = loadShape("data/hatyune/hatyune.obj");
    obj[1] = loadShape("data/hatyune/hatyune1.obj");
    obj[2] = loadShape("data/hatyune/hatyune2.obj");
    obj[3] = loadShape("data/hatyune/hatyune3.obj");
}

int c = 0; //カウンター

void draw(){
    if(cam.available() == false){
        return;
    }
    cam.read();
    marker.detect(cam);
    marker.drawBackground(cam);
    
    if(marker.isExist(0) == true){
        marker.beginTransform(0);
        lights();
        rotateX(PI/2);
        scale(50);
        shape(obj[c]); //配列の要素を指定
        marker.endTransform();
    }
    
    //drawのループに従ってカウンターを増やし、cが4になったら0に戻す
    c ++;
    if(c == 4){
        c = 0;
    }
}


これを実行すると、

はちゅねミクがネギを振るアニメーションになりました。


インタラクションを導入

正式な用語があるのかもしれませんが、ここでは「特定の操作をしたときにモデルの状態や動きが変わる」ことを「インタラクション」と呼んでいます。

回転しながら浮く箱に対して、2つ目のマーカーが検知されたときに回転が止まるようにしてみました。
(インタラクションという単語の意味とは少しずれてしまうかもしれませんが…)

import processing.video.*;
import jp.nyatla.nyar4psg.*;

Capture cam;
String[] cameras = Capture.list();
MultiMarker marker;
int hiro, kanji;
float c;

void setup(){
    size(640, 480, P3D);
    
    for(int i = 0; i < cameras.length; i ++){
        println("[" + i + "] " + cameras[i]);
    }

    cam = new Capture(this, cameras[1]);
    cam.start();
    
    marker = new MultiMarker(this, width, height, "../data/camera_para.dat", NyAR4PsgConfig.CONFIG_PSG);
    hiro = marker.addARMarker("../data/patt.hiro", 80);
    kanji = marker.addARMarker("../data/patt.kanji", 80);
}

void draw(){
    if(cam.available() == false){
        return;
    }
    cam.read();
    marker.detect(cam);
    marker.drawBackground(cam);
    
    if(marker.isExist(hiro) == true){
        marker.beginTransform(0);
        fill(0, 0, 255);
        translate(0, 0, 40);
        if(marker.isExist(kanji) == true){ //2つ目のマーカーが検知されたら
            c --; //回転を止める
        }
        rotateX(c/100);
        rotateY(c/100);
        box(40);
        marker.endTransform();
    }
    c ++;
}


まとめ

以上、ARで表示したモデルが動くようにしたり、ちょっとしたインタラクションができるようにしたりしてみました。