#概要
vvvvでopenFrameworksやProcessingからの映像を受け取って
出力したいという場合、SPOUT(http://spout.zeal.co/) を使います。
MacでいうところのSyphon(http://syphon.v002.info/) ですね。
SPOUTを使うことで他の言語で生成した映像をvvvvで受信したり、
逆にvvvvで作った映像をopenFrameworksなどに送ることがが可能になります。
この記事ではopenFrameworksで生成した映像をSPOUTを使って送信しvvvvで受信する方法を説明します。
送信側のopenFrameworksではSPOUTのDLLを使って映像を送信し、
受信側のvvvvではSpout_Receiver.v4pを使って映像を受信します。
vvvvは映像の送信も受信も簡単なんですがopenFrameworksはちょっと面倒でした。
(私がopenFrameworksにあまり詳しくないからかもですが。)
#準備 SPOUTのダウンロードとインストール
Spoutのダウンロードは http://spout.zeal.co/ のDownloadをクリックし
SpoutSetup_V2.004-beta.zipを入手します。
ZIPファイルを任意のフォルダに解凍しSpoutSetup_V2.004-beta.exeを実行すると
インストールが始まります。
インストール先はどこでもOKです。展開されたファイルを使うだけなので。
(※イントールの画像は抜粋です。)
インストール先のフォルダを確認するとSpout2のフォルダが以下のように展開されています。
この後に使うのは送信側がSpout2/SPOUTSDK/SpoutSDK/Binaries にあるSpout2.dll、Spout2.lib、SpoutDLL.hです。
受信側はSpout2/VVVV/Receiver/DirectX 9(11でもOK)にあるパッチファイルになります。
openFrameworksの実装については、\Spout2\SPOUTSDK\SpoutSDK\SPOUTDLL\cbSpoutExample\srcのソースをコピペし使います。
これらの場所を覚えておいてください。
#openFrameworks(0.9.0)でのSPOUT(Sender)の設定(Visual Studio 2015編)
openFrameworksでは新しいプロジェクトを作成した状態から説明します。
openFrameworksはとっかかりは http://yoppa.org/ をみればすべて書いてますのでそちらを参考にしてください。偉大です。
次にSpoutを使うための準備をします。Spout2.dll、Spout2.libをopenFrameworksのプロジェクトのbinフォルダにコピーします。
また、SpoutDLL.hをsrcフォルダにコピーします。
SpoutDLL.h をプロジェクトに追加します。
SolutionExplorerのsrcで右クリックし、Add>Existing Item で先ほど配置したSpoutDLL.hを選択すればOKです。
こんな感じでSolutionExplorerにSpoutDLL.hが追加されます。
次にSpout2.lib をLinkerに追加します。
Project>Vs2015Test(※プロジェクト名)PropertiesでPropertyPagesを開き
LinkerのInputを選択しAdditional Dependenciesでを選択し「.\bin\Spout2.lib」を
テキストボックスに記載し、OKをクリックします。
これで準備は整いました。
#ofApp.hの実装
次に実装です。
main.cppは特別編集は必要ありません。
ofApp.hではSpoutDLL.hをインクルードします。
#include "SpoutDLL.h" // for Spout2 dll
また、ofApp.cppで使う変数を定義しておきます。
ソースはインストール先の\Spout2\SPOUTSDK\SpoutSDK\SPOUTDLL\cbSpoutExample\src\ofApp.hの一部をコピペすればよいです。
void exit();
bool InitGLtexture(GLuint &texID, unsigned int width, unsigned int height);
char sendername[256]; // Shared memory name
GLuint sendertexture; // Local OpenGL texture used for sharing
bool bInitialized; // Initialization result
ofImage myTextureImage; // Texture image for the 3D demo
float rotX, rotY;
#ofApp.cppの実装
次にofApp.cppの実装です。
\Spout2\SPOUTSDK\SpoutSDK\SPOUTDLL\cbSpoutExample\src\ofApp.cppを参考に
必要なコードをコピペします。
まずはnamespaceを記載します。
// ====== SPOUT =====
using namespace Spout2;
次にsetup()の実装ですが以下のコードをサンプルからコピペします。
sendernameの文字列はvvvvと共通の文字列にする必要がありますが
適当でOKです。
// ====== SPOUT =====
bInitialized = false; // Spout sender initialization
strcpy(sendername, "CB Spout Sender"); // Set the sender name
ofSetWindowTitle(sendername); // show it on the title bar
// Create an OpenGL texture for data transfers
sendertexture = 0; // make sure the ID is zero for the first time
InitGLtexture(sendertexture, ofGetWidth(), ofGetHeight());
// Set the window icon from resources
//SetClassLong(GetActiveWindow(), GCL_HICON, (LONG)LoadIconA(GetModuleHandle(NULL), MAKEINTRESOURCEA(IDI_ICON1)));
// ===================
次にdraw()の実装です。
こちらは、SPOUTで送信したい範囲を
CreateSenderとSendTextureで囲む形になります。
//--------------------------------------------------------------
void ofApp::draw(){
char str[256];
ofSetColor(255);
// ====== SPOUT =====
// A render window must be available for Spout initialization and might not be
// available in "update" so do it now when there is definitely a render window.
if (!bInitialized) {
bInitialized = CreateSender(sendername, ofGetWidth(), ofGetHeight()); // Create the sender
}
// ===================
//ここから
ofDrawCircle(100.0, 100.0, 10.0, 15.0);
//ここまでが送信される。
// ====== SPOUT =====
if (bInitialized) {
if (ofGetWidth() > 0 && ofGetHeight() > 0) { // protect against user minimize
// Grab the screen into the local spout texture
glBindTexture(GL_TEXTURE_2D, sendertexture);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, ofGetWidth(), ofGetHeight());
glBindTexture(GL_TEXTURE_2D, 0);
// Send the texture out for all receivers to use
SendTexture(sendertexture, GL_TEXTURE_2D, ofGetWidth(), ofGetHeight());
//ここからの映像は送信されないのでUIとかを表示させてもいいかも
// Show what it is sending
ofSetColor(255);
sprintf(str, "Sending as : [%s]", sendername);
ofDrawBitmapString(str, 20, 20);
// Show fps
sprintf(str, "fps: %3.3d", (int)ofGetFrameRate());
ofDrawBitmapString(str, ofGetWidth() - 120, 20);
}
}
// ===================
}
あとはwindowResized、exit、InitGLtextureをサンプルからコピペして上書きすると
完了です。
//--------------------------------------------------------------
void ofApp::windowResized(int w, int h) {
// ====== SPOUT =====
// Update the sender texture to receive the new dimensions
// Change of width and height is handled within the SendTexture function
if (w > 0 && h > 0) // protect against user minimize
InitGLtexture(sendertexture, w, h);
}
//--------------------------------------------------------------
void ofApp::exit() {
// ====== SPOUT =====
ReleaseSender(); // Release the sender
}
// ====== SPOUT =====
bool ofApp::InitGLtexture(GLuint &texID, unsigned int width, unsigned int height)
{
if (texID != 0) glDeleteTextures(1, &texID);
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, 0);
return true;
}
ちょっと難しいのは最初のSpoutDLL.libの設定とか配置ですかね。。。
結構苦労しました。
コンパイルエラーの連続ですわ。
実装はコピペでいいので特に問題はないですかね。
#vvvvでSPOUT(Reviever)
次に受信側のvvvvの実装です。こちらはすこぶる簡単。
Spout2/VVVV/Receiver/DirectX 9/DX9_ReceiverExample.v4pを実行し、Spout_Receiverの
SpoutSenderNameの文字列を送信側の文字列を同じにするだけで受信できます。
今回はサンプルと同じく「CB Spout Sender」に変更してます。
vvvvではTextureが受信できるのであとはFullscreenQuadをかましてRendererにつなげれば
openFrameworksからの映像をvvvvで表示できます。
私は、vvvvでは手軽にエフェクトを変更したり出来るのでメインの映像はopenFrameworksでつくって
エフェクトとか画像の切り替えはvvvvでやるみたいな使い方をしてます。
全部vvvvでやればいいじゃないかって話ですが、まだまだ未熟で描きたい絵がvvvvで描けないので。
あと、openFramewoksでshaderを使った映像をvvvvに送るみたいな使い方をしてます。
するとGLSLSandBoxみたいなGLSLの映像もvvvvで扱えるようになるので。
(HLSLに移植したらいいじゃないって話ではありますが・・・。)
実装はこんな感じです。折角なんでopenFrameworksのHelloWorldともいえる(かどうかは知らんが)
3DPrimitivesExampleの映像をvvvvに送信して表示してみましょう。
vvvvのエフェクトをかけて最終的に出力してます。
こんな感じで、openFrameworksの映像をvvvvに送れるわけです。
ただ、送信側のウィンドウを最小化すると映像が止まってしまうとか、
送信側のウィンドウはプレビュー的に小さくして実際に送る映像は1280×800に
したいんだけどなーという感じがあるんですが解決方法がわからない。
SPOUT、oFに詳しい人がいたら教えてください。
#まとめ
vvvvがかなりマニアックなのにもかかわらず、さらにマニアックなSPOUTについての記事を書きました。需要は無いかもしれませんが、Windows環境ではSyphonは使えないので、openFrameworksのコンテンツをvvvvで活用したい人(そんな人いるかしら・・・)なんかのお役に立てれば幸いです。
どちらかというとopenFrameworksの記事ですか?みたいな話しもありますが・・・(汗
最終的にはvvvvを使ってるので良しとシテクダサイ。
あと、手さぐりで書いているので、SPOUT導入の正当なやりかたじゃないような気がしてます。
色々、ご指摘いただけると幸いです。また、質問があればどうぞ。
要望があればサンプルコードをGitHubにあげる・・・かもですが、SPOUTのサンプルで事足りる気もしてます。。。