現在、OpenGLの「glTexImage2D()」でうまく描画ができず困っています。
以下の手順で映像を取り込んで描画を行おうとしています。
①VC++にカメラ用のSDKをインクルードし、その機能で撮影した1フレームの画像を、RGBA情報を保持するためのbyte配列に格納する。(これを繰り返して映像として映し出す)
②OpenGLで視線方向を指定し、①で取り込んだ配列をテクスチャとして張り付けてモニタ上にレンダリングする。
①については単体で動作を確認したところ、配列に格納した値をPrintfで出力できたため問題ないと思います。
②についてはgClearやRectを用いて簡単に描画し、その状態での視線移動は正常にできていることを確認しました。(参考サイト:http://marupeke296.com/OGL_No1_Install.html)
しかし、①で作成したbyte配列をglTexImage2D()の引数に入れて実行したところ、画面上になにも表示されませんでした。タスクバーにアプリケーションが出るため、実行事態はできていると思います。
こちらが作成したプログラムです。Win32やOpenGLを始めたばかりなので、至らない点が多いとは思いますがよろしくお願いします。
そもそも他の方法でやったほうが処理が早いしラクだよという意見もあれば。
おそらく問題は、ウィンドウプロシージャ側のスクリプトにある「DrawScene()」の中だと思います。
_tWinMain側
#include <windows.h>
#include "resource.h"
// OpenGL
#include <tchar.h>
#include <gl/glut.h>
// FlyCapture
#include <FC1/pgrflycapture.h> // カメラの関数等(required:include directory "\Point Grey Research\FlyCaptureSDK\include\FC1")
#include <C/FlyCapture2_C.h>
#define TIMER_ID 1
typedef BOOL(WINAPI *PFNWGLSWAPINTERVALEXTPROC) (int interval); // wgl関数へのポインタ(VSYNC用)
extern PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT;
/////////////////////////////////////////////////////////////////////////////
/// 関数プロトタイプ ////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// _tWinMain()
bool InitApplications();
bool InitRegisterClass( HINSTANCE );
bool InitWindow( HINSTANCE, int);
bool FinalizeApplication();
// WindowProcedure()
LRESULT CALLBACK WindowProcedure( HWND, UINT, WPARAM, LPARAM );
bool InitOpenGL( HWND, HDC*, HGLRC* );
void InitCamera( int );
void FinalizeOpenGL( HGLRC ,HDC );
void DrawScene();
/////////////////////////////////////////////////////////////////////////////
/// 変数・構造体定義 ////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
const char *gName = "OpenGLテスト";
RECT _windowRect = { 0, 0, 800, 600 };
HWND _hWindow;
HGLRC _openglContext; // 作成ウィンドウ1のコンテキスト
HDC _hdc = NULL; // 初期化されていないかもよとエラーがでるので仕方なくお外
GLuint _textureID[2];
FlyCaptureContext _contextRight, _contextLeft;
FlyCaptureImage _imageRight, _imageLeft;
FlyCaptureImage _imageConvertedRight, _imageConvertedLeft;
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
unsigned char _pixelRight[640][480][4];
/////////////////////////////////////////////////////////////////////////////
/// メイン関数 //////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
MSG msg; HACCEL hAccelTable;
/// アプリケーションの初期化 ////////////////////////////////////////////////
if ( !InitRegisterClass( hInstance ) )
return -1;
if ( !InitWindow( hInstance, nCmdShow ) )
return -1;
hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_WIN32OGL);
/// メッセージループ ////////////////////////////////////////////////////////
do{
if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ){
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else {
/*
To do --命令が来ていないときに処理したいことがあればここに追加--
*/
}
} while ( msg.message != WM_QUIT )
return 0;
}
/////////////////////////////////////////////////////////////////////////////
/// ウィンドウクラスの生成を行う ////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
bool InitRegisterClass( HINSTANCE hInstance )
{
// 生成するウィンドウクラスの設定
WNDCLASSEX wcex = { sizeof(WNDCLASSEX), CS_HREDRAW | CS_VREDRAW,WindowProcedure,0,0,hInstance,NULL,NULL,(HBRUSH)(COLOR_WINDOW + 1),NULL,(TCHAR*)gName,NULL };
// ウィンドウクラスの生成
if ( (ATOM)0 == RegisterClassEx( &wcex ) ){
//printf("ウィンドウクラスの生成に失敗しました.\n");
return false;
}
return true;
}
/////////////////////////////////////////////////////////////////////////////
/// ウィンドウの生成を行う //////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
bool InitWindow(HINSTANCE hInstance ,int nCmdShow)
{
// ウィンドウを生成する
_hWindow = CreateWindow(gName,gName,WS_VISIBLE | WS_POPUP, 0, 0,_windowRect.right - _windowRect.left,_windowRect.bottom - _windowRect.top,NULL, NULL, hInstance, NULL);
// ウィンドウ作成データ (WM_CREATEでLPARAMに渡したい値)
if ( _hWindow == NULL )
return false;
ShowWindow(_hWindow, nCmdShow);
UpdateWindow(_hWindow);
SetTimer(_hWindow, TIMER_ID, 20, NULL);
return true;
}
ウィンドウプロシージャ側
LRESULT CALLBACK WindowProcedure(HWND _hWindow,UINT message,WPARAM wParam,LPARAM lParam)
{
PAINTSTRUCT ps;
RECT rect;
switch (message){
case WM_CREATE:
InitOpenGL( _hWindow, &_hdc, &_openglContext); //下に関数
wglMakeCurrent( _hdc, _openglContext);
InitCamera(0); //下に関数
wglMakeCurrent(NULL, NULL);
ReleaseDC( _hWindow, _hdc );
break;
case WM_PAINT:
_hdc = BeginPaint(_hWindow, &ps); // 更新領域を初期化
wglMakeCurrent(_hdc, _openglContext); // レンダリングコンテキストをカレントに
DrawScene();
wglMakeCurrent(NULL, NULL); // レンダリングコンテキストをカレントから外す
EndPaint(_hWindow, &ps); // 更新領域を空に戻す
break;
case WM_TIMER:
InvalidateRect( _hWindow , NULL, false); // 再描画のメッセージを送る
break;
case WM_ERASEBKGND: // 背景を消さない
return TRUE;
// キー入力が発生した場合
case WM_KEYDOWN:
switch (wParam){
// [ESC]キーが押された場合,ウィンドウを削除する
case VK_ESCAPE:
DestroyWindow( _hWindow );
break;
}
break;
case WM_DESTROY:
PostQuitMessage(0); //レンダリングコンテキストの削除
FinalizeOpenGL(_openglContext, _hdc);
break;
default:
return DefWindowProc( _hWindow, message, wParam, lParam);
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////
/// OpenGLで描画を行うように設定 ////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
bool InitOpenGL(HWND hWindow,HDC *_hdc,HGLRC *_openglContext)
{
// ピクセルフォーマットの作成
PIXELFORMATDESCRIPTOR pixelForMatdescriptor = {sizeof(PIXELFORMATDESCRIPTOR),1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA,32,0, 0, 0, 0, 0, 0,0,0,0,0, 0, 0, 0,24,8,0, PFD_MAIN_PLANE,0,0, 0, 0};
// 生成したウィンドウのディスプレイデバイスコンテキスト(ウィンドウの挙動を決定できる箱)のハンドルを取得 (OpenGLで描写したいウィンドウを指定する)
*_hdc = GetDC( hWindow );
if (_hdc == NULL)
return false;
// hWindowの領域を_windowRectに格納する
GetClientRect( hWindow, &_windowRect );
// デバイスコンテキストに適したピクセルフォーマットを取得
int format = ChoosePixelFormat( *_hdc, &pixelForMatdescriptor );
if ( format == 0 )
return false;
// OpenGLが使うデバイスコンテキストに指定のピクセルフォーマットをセット
if ( !SetPixelFormat( *_hdc, format, &pixelForMatdescriptor ) )
return false;
// OpenGL contextを作成
*_openglContext = wglCreateContext( *_hdc );
// 作成されたコンテキストをカレント(実行状態)にする
if (!wglMakeCurrent(*_hdc, *_openglContext))
return false;
// 垂直同期をとる用
wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
if (wglSwapIntervalEXT)
wglSwapIntervalEXT(1);
wglMakeCurrent(NULL, NULL);
ReleaseDC(_hWindow, *_hdc);
return true;
}
/////////////////////////////////////////////////////////////////////////////
/// カメラの初期化処理 //////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void InitCamera( int cameraNum ){
if (cameraNum == 0){
// FlyCaptureカメラのコンテキストを作成
flycaptureCreateContext(&_contextRight);
// カメラの初期化
printf("Initializing Right Camera.\n");
flycaptureInitialize(_contextRight, 0);
printf("Starting Right Camera.\n\n");
flycaptureStart( _contextRight,FLYCAPTURE_VIDEOMODE_640x480RGB,FLYCAPTURE_FRAMERATE_30);
// 変数の初期化
memset(&_imageRight, 0x0, sizeof(FlyCaptureImage));
memset(&_imageConvertedRight, 0x0, sizeof(FlyCaptureImage));
_imageConvertedRight.pData = new unsigned char[sizeof(_pixelRight)];
_imageConvertedRight.pixelFormat = FLYCAPTURE_BGRU;
}
// 有効無効
glEnable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glGenTextures(1, &_textureID[cameraNum]);
glBindTexture(GL_TEXTURE_2D, _textureID[cameraNum]);
// 拡大縮小の設定
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
// ウィンドウ全体をビューポートにする
glViewport(0, 0, 800, 600);
// 透視変換行列の指定
glMatrixMode(GL_PROJECTION);
// 透視変換行列の初期化
glLoadIdentity();
gluPerspective(25.0, 800 / 600, 1.0, 100.0); // 透視変換行列を視野角で設定する
}
/////////////////////////////////////////////////////////////////////////////
/// OpenGLの解放処理(問題のシーン) ///////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
void DrawScene(){
flycaptureGrabImage2(_contextRight,&_imageRight);
unsigned char *ptr1;
for (int i = 0; i < 640; i++){
ptr1 = &(_imageRight.pData[i * _imageRight.iRowInc]);
for (int j = 0; j < 480; j++)
{
_pixelRight[i][j][0] = ptr1[0];
_pixelRight[i][j][1] = ptr1[1];
_pixelRight[i][j][2] = ptr1[2];
_pixelRight[i][j][3] = 255;
ptr1 += 3;
}
}
/// 指定ウィンドウへの描画設定 //////////////////////////////////////////////
wglMakeCurrent(_hdc, _openglContext);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/// 空間の設定 //////////////////////////////////////////////////////////////
glClear(GL_COLOR_BUFFER_BIT);
glBindTexture(GL_TEXTURE_2D, _textureID[0]);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA, 640, 480,
0, GL_RGBA, GL_UNSIGNED_BYTE, _contextRight
);
glBegin(GL_QUADS);
glNormal3d(-1.0, 0.0, 0.0);
glTexCoord2d(0.0, 1.0);
glVertex3d(4.5, -1.3275, -1.3275);
glTexCoord2d(1.0, 1.0);
glVertex3d(4.5, -1.3275, 1.3275);
glTexCoord2d(1.0, 0.0);
glVertex3d(4.5, 1.3275, 1.3275);
glTexCoord2d(0.0, 0.0);
glVertex3d(4.5, 1.3275, -1.3275);
glEnd();
glFlush(); // ここまでバッファ上で処理したものを実際にレンダリングする
glBindTexture(GL_TEXTURE_2D, 0);
/// 視点の設定 //////////////////////////////////////////////////////////////
glMatrixMode(GL_MODELVIEW); // モデルビューにする
glLoadIdentity(); // 変換処理が累積した変換行列の初期化
gluLookAt(
0.0, 0.0, 0.0, // 視点の位置x,y,z;
0.0, 0.0, 0.0, // 視界の中心位置の参照点座標x,y,z
0.0, 1.0, 0.0); // 視界の上方向のベクトルx,y,z
SwapBuffers(_hdc); // Windows APIのほうでデバイスコンテキストをスワップするらしい ()
wglMakeCurrent(NULL, NULL); // ウィンドウ1の描画を終了
}
Win32とOpenGL以外で実現しようとしたこと。
・FlyCaptureのdllをUnityで読み込んでGUI周りの簡略化
→C#でのダブルポインタやC++とのメモリの取り方の違いあたりで断念
・処理をOpenCVでさせる
→OpenGLすら分かっていないのに、CVにまで手を出すとやばそうと思い断念
開発環境
・OS :Windows 7 64bit
・ソフト:Visual Studio 2013 Express for Windows Desktop
・カメラ:FL2-03S2C(Point Grey Reserch社)
・glut :freeglut3.0.0 (導入の参考にしたサイト:https://tokoik.github.io/opengl/libglut.html)