mieki256's diary



2022/09/18() [n年前の日記]

#1 [python] PyOpenGLでボールが跳ね回るスクリプトを作成

PyOpenGL を使って、ボールが箱の中で跳ね回るスクリプトを書いてみた。

動作確認環境は以下。
動かすとこんな感じ。




以下のキーが有効。 FPS表示時の赤い線は、期待した60FPSに対して実際何FPS出ているかを、箱の一辺の長さとの比較で表示している。60FPSが出ていれば、赤い線は箱の一辺と同じ長さになるし、それより少ないFPSなら、箱の一辺より短く表示される。

ソース。 :

ソースは GitHub Gist にアップロードしてみた。このページにも埋め込めるだろうか…。どうかな…。

_01_bound_ball.py (Gist)


以降、ソースの中身について、少しだけ解説。

FPSの計測について。 :

FPSの計測は、1秒間に何回画面を書き換えたかをカウントする方法で調べた。init_count_fps()、calc_fps() を見れば、どうやっているか分かるかなと…。

時間の取得には、time.time() を使った。import time をすれば使えるようになる。time.time() を呼ぶと、その時点の時刻が、秒単位(小数点以下も含む状態)で得られるらしい。

Python 2.7.18 32bitの場合、time.time() の返り値は小数点以下3桁まで含んでいる。ミリ秒まで分かるのだろう…。
>>> import time
>>> time.time()
1663505711.946
>>> time.time()
1663505714.521

Python 3.9.13 64bitの場合、time.time() の返り値は、小数点以下7桁まで得られる模様。もしかすると、マイクロ秒まで得られる…?
>>> import time
>>> time.time()
1663505644.9368925
>>> time.time()
1663505648.3456943

まあ、Python 2.7 の場合を考えて、time.time() は少なくともミリ秒まで分かると思って使えばいいのかなと。

ちなみに、最初は時間の取得に time.perf_counter() を使っていたのだけど。time.perf_counter() は Python 3.3 で実装されたメソッドだから Python 2.7 では動かなくて、time.time() で置き換えることになった。

文字描画について。 :

OpenGL で画面に文字を描画するあたりは、GLUT (freeglut) の glutBitmapCharacter() を利用した。GLUT (freeglut) を利用できる状況じゃないと使えないけれど…。

_情報メディア実験
_glutBitmapCharacter : PyOpenGL 3.1.0 GLUT Man Pages
_~mcfletch/openglcontext/trunk : contents of tests/glutbitmapcharacter.py at revision 699
_python - pyopengl How to render text - Stack Overflow

文字を描画する際の位置決めは、最初、glRasterPos3f(x, y, z) を使ってみたのだけど、glWindowPos2f(x, y) というメソッドもあると知って、そちらを使うようにしてみた。

_glRasterPos : PyOpenGL 3.1.0 GL Man Pages
_glWindowPos : PyOpenGL 3.1.0 GL Man Pages

この glWindowPos2f() を使えば、3D空間内の位置ではなく、ウインドウ上の2D的な感覚で座標指定ができる。

ただし、注意点が2つほどある。
  • 画面左下が (0, 0) になっている。
  • OpenGL 1.4 から追加されたメソッドなので、OpenGL 1.1 等では使えない。
例えば、Windows に標準で入ってる OpenGL は 1.1 対応だそうで、そのせいか、C/C++ で書いたプログラム等で glWindowPos2f() を使おうとすると「そんなAPIは無い」と言われてしまう。

もっとも、今時のPCなら、ビデオドライバはもっと後の OpenGLバージョンにも対応してるだろうから…。もしかすると、PyOpenGLを使う時はそのあたりを上手い具合に変更してくれて、それで今回 glWindowPos2f() が使えているのかもしれない。たぶん。分からんけど。

アニメーション処理について。 :

アニメーションをするためには一定の時間間隔で処理を呼ばないといけないけれど、そのあたりは glutTimerFunc() で指定している。

_glutTimerFunc : PyOpenGL 3.1.0 GLUT Man Pages
_GLUT のイベント

巷の解説ページでは glutIdleFunc() を使う場合が多いのだけど…。glutIdleFunc() に渡す関数は引数を取らないけれど、glutTimerFunc() に渡す関数は引数を1つ取るので、その点はちょっとだけ注意。

#2 [prog] C言語とOpenGLでボールが跳ね回るプログラムを作成

_PyOpenGLを使ってボールが箱の中で跳ね回るスクリプトを書いた わけだけど、これをC言語 + OpenGL で動くように移植してみた。

環境は、Windows10 x64 21H2 + MinGW (gcc 9.2.0) + freeglut 3.0.0。MSYS2 + MinGW-w64 ではなくて、MinGW + MSYS でコンパイルしている。

MinGW用の freeglut 3.0.0 バイナリ (freeglut-MinGW-3.0.0-1.mp.zip) は、以下から入手させてもらった。ありがたや。

_freeglut Windows Development Libraries

動作画面は PyOpenGL版と大体同じ。

以下のキーを受け付ける。

ソース。 :

コンパイル。 :

Makefile があるので、make と打てばコンパイルできるだろうけど…。一応、コンパイルは以下。01_gl_bound_ball.exe が生成される。
gcc 01_gl_bound_ball.c -o 01_gl_bound_ball.exe -static -D FREEGLUT_STATIC -lfreeglut_static -lopengl32 -lglu32 -lwinmm -lgdi32 -mwindows

01_gl_bound_ball.exe を実行すれば、PyOpenGL版と同じ見た目のウインドウが開くかと。

覚書。 :

FPS表示時に、一応「FPS: xx」の文字描画もしてみたけれど、glWindowPos2f() が使えなかったので、 *1 glRasterPos3f() を使うことになった。そのせいで、箱の上のほうに「FPS: xx」がくっついて動いてる表示になってしまった。ちょっとダサイ。ウインドウの特定の位置に固定して表示したかったのだけど、このあたり本来はどうやって解決すればいいのやら。

一般的に、C言語で円周率を使いたい時は、math.h をインクルードして(#include <math.h>)、M_PI を利用するらしいのだけど。試してみたら Visual Studio Code 上で「このシンボルは見当たらないよ」と言われてしまった。math.h を include する前に、「#define _USE_MATH_DEFINES」を書いておけば、その手のマクロが使えるようになるらしい。ただ、移植性は落ちるそうで…。

_定数M_PIが使えない - 需要のないページ
_プログラミングメモ日記 C++での数学定数の利用について
_M_PI ‐ 通信用語の基礎知識
_C言語(標準)にM_PIは無い - 簡潔なQ
_math.h の M_PI などは仕様外だった - GUST NOTCH? DIARY

*1: glWindowPos2f() は OpenGL 1.4 から使える。OpenGL 1.1 では使えない。

以上、1 日分です。

過去ログ表示

Prev - 2022/09 -
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project