Windows 10で昔ながらのOpenGLを使った3DのCGの表示

Windows 10で昔ながらのOpenGLを使った3DのCGの表示というのをやってみた。(2020年に いまさらOpenGL、、)

なぜ3DのCGかというと、最近M5Stack/M5StickCマイコンを使ってIMU(慣性計測ユニット)のジャイロセンサーと加速度センサーと地磁気センサーの出力の合計9軸分を計測して、9DoFの出力を取得するというのを趣味で作り中で、その出力結果をPCで3DのCGで表示して確認したかったからだ。

昔、ジャイロセンサー無しで加速度センサーと地磁気センサーだけを使って6DoFの計測をして、物体の向き(姿勢)を計算して、3DのCG表示をさせるというのを作っていたことがある。そのときに使ったのがOpenGLだった。というか、自分はそれしか3DのCGのライブラリを知らない。当時はOpenGLをWindows上(Windows XP~Windows7)で使っていた。OpenGL 1.1くらいの時だ。

今(2020年)、OpenGLをWindows 10上で使うにはどうするのがよいのか、調べてみた。

1.OpenGLを使う方法

 本家のOpenGLは、もうWindows用とかで使えるアプリ開発用ライブラリを公開していないし、配布もしていない。
 参考: OpenGL – Wikipedia
 ただし、機能としてはWindowsにXPの時代くらい(?)からずっとOpenGLはOSに組み込まれていて、Windows10でもちゃんと残っているので、APIを叩けばOpenGLの機能は使うことができる。(OSに組み込まれているというよりは、NVIDIAとかのGPUのドライバにいまだに組み込まれているというべきかも。)
 追記、
 OpenGL自体をインストールしなくても、まだ配布されているGLUTというライブラリだけダウンロードして使えばちゃんとOpenGLを使用できるそうだ。
 GLUT公式: GLUT – The OpenGL Utility Toolkit

2.freeGLUTを使う方法

 OpenGL互換のfreeGLUTというプロジェクトは、OpenGLのライブラリの公開終了後も開発がしばらく続いていたが、SourceForgeにあったプロジェクトページは無くなってしまっている。もうソースコードは入手できないようだ。個人のホームページでライブラリのバイナリを配布しているページが見つかるので、そちらから現在でもバイナリとしては入手は可能だ。
 しかし、このライブラリを組み込んだ実行ファイルをVisualStudio2019でビルドして生成して、実行しようとしてみたところ、Windows Defenderが反応してウイルスと反応してしまって実行できず、そのあと数十秒後に勝手にexeファイルが自動削除されてしまった。ダウンロードした実行ファイルが安全でないということでブロックされる現象に似ているのだが、それよりも強い警告でブロックされて、その画面には実行を可能にする選択肢は無い。自動削除されてしまう前に実行ファイルを右クリックからのWindowsDefenderでチェックする機能を使ってチェックし、ウイルスが検出されたという表示が出てくる画面にて、選択肢が削除と検疫と許可というのが出てくるので、許可をすると削除されなくなり、実行ができるようになる。
 こんな状態だと自分のプロジェクトにfreeGLUTを組み込んだものを使うのは気持ち悪いし、他人に実行ファイルを配布したあと、ウイルス誤認問題が発生したら面倒なことになるので、配布するソフトにfreeGLUTを組み込むのは避けたほうがよさそうだ。

3.SDLを使う方法

 SDL(Simple DirectMedia Layer)というライブラリがあり、これもOpenGLのAPIをサポートしている。2020年でもまだプロジェクトとしては生きていて、開発や配布は続いている。
 ただし、使用できるのはOpenGLの基本のライブラリのみで、OpenGLのGLUTで拡張された便利な機能は持っていない。ポリゴンを構成する座標データとか自分で管理して表示させるしかないので、簡単な直方体くらいまでは表示するのはそこまで長いコードを書かなくても楽にできるのだが、複雑なことをやらせようとするとかなり自前でコードを書かなくてはならない。
 昔、WiiリモコンhackをしたときにWiiリモコンの動きを表示させるソフトを作るのにSDL 1.2使ってみたことがあった。
 今回SDL 1.2系の最終版を試しに動かしてみたが、普通に動かすことができた。
 だだ、最新のSDL 2.xについては簡単には差し替えられ無さそうだった。2.xへの以降は保留だ。

次のようなコードをVisual Studio 2019で32bit版のSDLを使ってビルドして動かしてみた。

#include <windows.h> 
#include <process.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> 
#include <math.h>
#include "SDL/SDL.h"
#include "SDL/SDL_opengl.h"

#define ACC_GAIN 26

#ifdef __cplusplus
FILE iob[] = { *stdin, *stdout, *stderr };
extern "C" {
    FILE * __cdecl _iob(void) { return iob; }
}
#endif

int HandleEvent(SDL_Event *event)
{
	int done;
	done=0;
	switch( event->type ) {
		case SDL_KEYDOWN:
			//printf("key '%s' pressed\n", SDL_GetKeyName(event->key.keysym.sym));
			if ( event->key.keysym.sym == SDLK_ESCAPE ) { done=1; }
			break;
		case SDL_QUIT:
			done=1;
			break;
	}
	return done;
}

int Do_sdl_event()
{
	int done;
	done=0;
	SDL_Event event;
	while( SDL_PollEvent(&amp;event) ) {
		done=HandleEvent(&amp;event);
	}
	return done;
}

int RunGLTest()
{
	Uint32 video_flags;
	int value;
	int bpp = 0;
	int rgb_size[3];
	int w = 640;
	int h = 480;
	int done = 0;
	static float jx=0,jy=0,jz=0;
	GLenum gl_error;
	char* sdl_error;
	float cube[8][3]= {
		{ 0.5,  0.4, -1.5}, { 0.5, -0.4, -1.5}, {-0.5, -0.4, -1.5}, {-0.5,  0.4, -1.5},
		{-0.5,  0.4,  1.5}, { 0.5,  0.4,  1.5}, { 0.5, -0.4,  1.5}, {-0.5, -0.4,  1.5}  };
	
	putenv("SDL_VIDEODRIVER=directx");
	if( SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK) < 0 ) {
		printf("Couldn't initialize SDL: %s\n",SDL_GetError());
		exit( 1 );
	}
	
	SDL_ShowCursor(SDL_DISABLE);

	video_flags = SDL_OPENGL;
	if ( SDL_GetVideoInfo()->vfmt->BitsPerPixel <= 8 ) { bpp=8; } else { bpp=16; }
	switch (bpp) {
		case 8:  rgb_size[0]=3; rgb_size[1]=3; rgb_size[2]=2; break;
		case 16: rgb_size[0]=5; rgb_size[1]=5; rgb_size[2]=5; break;
		default: rgb_size[0]=8; rgb_size[1]=8; rgb_size[2]=8; break;
	}
	SDL_GL_SetAttribute( SDL_GL_RED_SIZE,   rgb_size[0] );
	SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, rgb_size[1] );
	SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE,  rgb_size[2] );
	SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
	SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
	SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
	SDL_GL_SetAttribute( SDL_GL_ACCELERATED_VISUAL, 1 );
	SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 1 );
	if ( SDL_SetVideoMode( w, h, bpp, video_flags ) == NULL ) {
		printf("Couldn't set GL mode: %s\n", SDL_GetError());
		SDL_Quit(); getch(); exit(1);
	}

	SDL_WM_SetCaption( "GL-test", "testgl" );

	glViewport( 0, 0, w, h );
	glMatrixMode( GL_PROJECTION );
	glLoadIdentity( );
	glOrtho( -2.0, 2.0, -2.0, 2.0, -20.0, 20.0 );
	glMatrixMode( GL_MODELVIEW );
	glLoadIdentity( );
	glEnable(GL_DEPTH_TEST);
	glDepthFunc(GL_LESS);
	glShadeModel(GL_SMOOTH);

	while( !done ) {
		jx = jx+0.1;
		jy = jy+0.25;
		jz = jz+0.314;
		
		glClearColor( 0.0, 0.0, 0.0, 1.0 );
		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		
		glMatrixMode(GL_MODELVIEW);
		
		glLoadIdentity(); // Matrix reset
		
		// Rotation
		glRotatef(jz , 0, 1.0, 0);
		glRotatef(jy, 1.0, 0, 0);
		glRotatef(jx, 0, 0, 1.0);
	
		// draw CUBE
		glBegin( GL_QUADS );
		 glColor3f(1.0, 1.0, 1.0);
		 glVertex3fv(cube[0]);glVertex3fv(cube[1]);glVertex3fv(cube[2]);glVertex3fv(cube[3]);
		 glColor3f(0.9, 0.9, 0.9);
		 glVertex3fv(cube[3]);glVertex3fv(cube[4]);glVertex3fv(cube[7]);glVertex3fv(cube[2]);
		 glColor3f(0.8, 0.8, 0.8);
		 glVertex3fv(cube[0]);glVertex3fv(cube[5]);glVertex3fv(cube[6]);glVertex3fv(cube[1]);
		 glColor3f(0.7, 0.7, 0.7);
		 glVertex3fv(cube[5]);glVertex3fv(cube[4]);glVertex3fv(cube[7]);glVertex3fv(cube[6]);
		 glColor3f(1.0, 1.0, 1.0);
		 glVertex3fv(cube[5]);glVertex3fv(cube[0]);glVertex3fv(cube[3]);glVertex3fv(cube[4]);
		 glColor3f(0.8, 0.8, 0.8);
		 glVertex3fv(cube[6]);glVertex3fv(cube[1]);glVertex3fv(cube[2]);glVertex3fv(cube[7]);
		glEnd( );
		
		SDL_GL_SwapBuffers( );
		
		// GL error check ,  SDL error check
		gl_error = glGetError( );   sdl_error = SDL_GetError( );
		if( gl_error != GL_NO_ERROR ) {
			printf("testgl: OpenGL error: %d\n", gl_error );
		}
		if( sdl_error[0] != '\0' ) {
			printf("testgl: SDL error '%s'\n", sdl_error); SDL_ClearError();
		}
		
		// SDL event process
		done=Do_sdl_event();
		
		// wait
		SDL_Delay(10);
	}
	
	SDL_Quit();
	return 0;
}


int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow )
{
	RunGLTest();
	return 0;
}

そこそこ短いコードで3DのCGを動かすことができた。GLUTを使えばもう少し楽なのだけど。
(前に動かしてみたのと同じだが、Windows10上でVisual Studio 2019で動かすことができた。)

(その他、OpenGL用のライブラリとかあるかもしれないですが、よく分からないので使っている人とかコメントで教えて頂けるとありがたいです。)


結論としては、OpenGLについてはこんなありさまだったので、短いコードで簡単に 3DのCG表示ができるライブラリとして使い続けるのは難しいかなあと思った。

DXライブラリでDirectXの3D CG機能を使うことができ、そちらの方がよさそうということで、試し中。

1 thought on “Windows 10で昔ながらのOpenGLを使った3DのCGの表示

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

Time limit is exhausted. Please reload CAPTCHA.

32 − = 31