2017/02/07(火) [n年前の日記]
#1 [ruby][gosu] Ruby + Gosu + opengl の動作確認
Windows10 x64上で、
_Ruby 2.2.6p396 mingw32
+
_gosu 0.11.1
+
_opengl 0.9.2
を使って、OpenGLの描画ができそうか実験。
ちなみに、Ruby というのはプログラミング言語の一つで…。そのRubyを使って2Dゲームを作れるライブラリとして、gosu というのがあって。という説明でいいのだろうか。
Ruby を使ってゲームを作れるライブラリとしては、他にも DXRuby があるけれど。
ちなみに、Ruby というのはプログラミング言語の一つで…。そのRubyを使って2Dゲームを作れるライブラリとして、gosu というのがあって。という説明でいいのだろうか。
Ruby を使ってゲームを作れるライブラリとしては、他にも DXRuby があるけれど。
- DXRuby ... DirectXを使うのでWindows専用(なのだけど、Linux上ではWineを使うと動かすこともできるらしい)。3D描画機能は無い。Sprite等の便利なクラスがある。
- gosu ... Windows、Mac、Linuxで動く。opengl というライブラリと組み合わせて使えば3D描画もできる。DXRubyほど便利なクラスは用意されてない。比較的、最低限の機能だけを揃えてある雰囲気。
◎ OpenGLが動くかどうかだけを確認。 :
まずは gosu と関係なく、opengl というライブラリが動くかどうかを確認。以下のページを参考に、というかそのままコピペさせてもらって試してみたり。ありがたや。
_RubyでOpenGL - verus diary
_ruby-openglでお手軽3Dプログラミング | Gemの紹介 | DoRuby
_MF / Ruby で OpenGL
opengl、glu、glut なるライブラリをインストールする。Rubyがインストールされてる環境なら、以下でインストールできる。
ところで、GLU とか GLUTって何だろう?
_OpenGL Utility Toolkit - Wikipedia によると…。
さておき。動作確認したソースはこんな感じに。
_opengl_glut_only_test.rb
こういう結果になった。ティーボットが表示された。
ソースの中にコメントを書きまくったので、ソースを見れば何をやってるか大体分かるかなと。
_RubyでOpenGL - verus diary
_ruby-openglでお手軽3Dプログラミング | Gemの紹介 | DoRuby
_MF / Ruby で OpenGL
opengl、glu、glut なるライブラリをインストールする。Rubyがインストールされてる環境なら、以下でインストールできる。
gem install opengl gem install glu gem install glut
ところで、GLU とか GLUTって何だろう?
_OpenGL Utility Toolkit - Wikipedia によると…。
- OpenGL Utility Library の略で「GLU」。
- OpenGL Utility Toolkit の略で「GLUT」。
さておき。動作確認したソースはこんな感じに。
_opengl_glut_only_test.rb
# gosu + opengl のテスト
# とりあえず、opengl + glut のテストだけをしてみる。
require "opengl"
require "glut"
require "glu"
# 表示処理
display = proc {
GL.Clear(GL::COLOR_BUFFER_BIT) # カラーバッファをクリア
GL.Color3f(0.0 , 1.0 , 0.0) # 色を指定
GLUT.WireTeapot(0.5) # ティーポットを表示
GLUT.SwapBuffers() # 画面を入れ替え(ダブルバッファ)
}
# ウインドウが変形したり最初に生成された際に呼ばれる処理
reshape = proc { |w, h|
GL.Viewport(0, 0, w, h) # ビューポートを設定
GL.MatrixMode(GL::GL_PROJECTION) # 演算ターゲットを射影行列に
GL.LoadIdentity() # 変換行列を単位行列に
GLU.Perspective(30.0, w.to_f/h, 1.0, 100.0) # 透視投影を指定
GL.MatrixMode(GL::GL_MODELVIEW) # 演算ターゲットをモデルビュー行列に
GL.LoadIdentity() # 変換行列を単位行列に
GLU.LookAt(3.0, 2.0, 1.0, # カメラ位置
0.0, 0.0, 0.0, # 注視点の位置
0.0, 1.0, 0.0 # どっちが上かを指定
);
}
# 一定時間ごとに呼ばれる処理
timer = proc {
GL.Rotate(2.0, 0.0, 1.0, 0.0) # Y軸を回転 (ang, x, y, z)
GLUT.PostRedisplay() # 再描画を要求
GLUT.TimerFunc(16, timer, 0) # 16ms毎に呼び直す
}
GLUT.Init() # GLUTの初期化
GLUT.InitWindowSize(512, 512) # ウインドウサイズを指定
GLUT.CreateWindow("OpenGL:Teapot") # ウインドウを生成
GLUT.DisplayFunc(display) # ディスプレイコールバックの登録
GLUT.ReshapeFunc(reshape) # リシェイプコールバックの登録
GLUT.TimerFunc(10, timer, 0) # 一定時間ごとに呼ばれる処理を登録
GL.ClearColor(0.2,0.2,0.2,0.0) # 画面クリア時の色を指定
GLUT.MainLoop() # メインループ
こういう結果になった。ティーボットが表示された。
ソースの中にコメントを書きまくったので、ソースを見れば何をやってるか大体分かるかなと。
◎ gosu + opengl で3D描画の動作確認。 :
gosu と opengl を組み合わせて、3D描画ができるのか確認してみる。gosu + opengl ができると何が嬉しいかと言うと…。例えば、「背景は3D描画でカッコよく」「だけど手前は2D描画・2Dゲームで」みたいなことができる、かもしれない。要は、2Dゲーム内でも演出として3D描画を使えるかもしれないよね、みたいな。
gosu には、 _gosu-examples という、サンプルファイルがいくつか入ったライブラリ(?)が用意されている。その中の _gosu-examples/opengl_integration.rb が、gosu + opengl のサンプルになっていて。
件のサンプルの中から、gosu の描画関係を省いて、opengl の描画部分だけを残して色々弄って動作確認してみたり。
ちなみに、gosu のインストールは以下でできる。
動作確認に使ったソースは以下。
_gosu_opengl_test1.rb

_uv.png
こういう結果に。それっぽく描画されている、ような気がする。
gosu で opengl を使う手管は…。基本的には、gosu と gl を require して。
OpenGLで描画したい箇所で、
_Method: Gosu.gl - Documentation for gosu/gosu (master)
上記のドキュメントによると、注意事項として…。
また、 _GitHub - tjbladez/gosu-opengl-tutorials: Fun with opengl, gosu and ruby によると、もうちょっと違う書き方もできるのかもしれない。
_gosu-opengl-tutorials/lesson01.rb を眺めた感じでは、Gosu::Window を継承したクラスのdraw内で、
gosu には、 _gosu-examples という、サンプルファイルがいくつか入ったライブラリ(?)が用意されている。その中の _gosu-examples/opengl_integration.rb が、gosu + opengl のサンプルになっていて。
件のサンプルの中から、gosu の描画関係を省いて、opengl の描画部分だけを残して色々弄って動作確認してみたり。
ちなみに、gosu のインストールは以下でできる。
gem install gosu
動作確認に使ったソースは以下。
_gosu_opengl_test1.rb
# gosu + opengl の動作確認
# gosu-examplesの opengl_integration.rb を弄って、
# OpenGL 絡みの部分だけを列挙
# 横スクロールで地形の上を進むイメージで描画
require 'gosu'
require 'gl'
WIDTH, HEIGHT = 640, 480
# OpenGLを使って背景描画するためのクラス
class GLBackground
# Height map size
POINTS_X = 16
POINTS_Y = 16
# Scrolling speed
SCROLLS_PER_STEP = 20
# 初期化
def initialize
@image = Gosu::Image.new("uv.png", :tileable => true) # テクスチャ読み込み
@scrolls = 0
@height_map = Array.new(POINTS_Y) { Array.new(POINTS_X) { rand } }
end
# 更新処理
def update
@scrolls += 1
if @scrolls == SCROLLS_PER_STEP
@scrolls = 0
@height_map.shift
@height_map.push Array.new(POINTS_X) { rand }
end
end
# 描画処理
def draw(z)
# Gosu.gl(z値)でOpenGLの描画を行う
# 描画後、Gosuの描画ができるようにしてくれるらしい
Gosu.gl(z) { exec_gl }
end
private
include Gl
# OpenGL関係の処理
def exec_gl
glClearColor(0.2, 0.2, 0.2, 1.0) # 画面クリア色を指定 (r,g,b,a)
glClearDepth(1.0) # デプスバッファをクリア
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 画面クリア
# テクスチャ情報が取得できないなら何もせずに戻る
info = @image.gl_tex_info
return unless info
# 奥行き比較関数の種類を指定。デフォルトではGL_LESSが指定されてるらしい
# glDepthFunc(GL_GEQUAL)
glDepthFunc(GL_LESS)
glEnable(GL_DEPTH_TEST) # デプスバッファを使う
# glEnable(GL_BLEND) # アルファブレンドを有効化
glMatrixMode(GL_PROJECTION) # 透視投影の設定
glLoadIdentity
# glFrustum(-0.10, 0.10, -0.075, 0.075, 1, 100)
glFrustum(-0.04, 0.04, -0.075, 0.075, 0.1, 100)
glMatrixMode(GL_MODELVIEW) # モデルビュー変換の指定
glLoadIdentity
glRotate(35.0, 1.0, 0.0, 0.0) # 回転させる (ang, x, y, z)
glTranslate(0, -0.35, -0.8) # 位置をずらす
glEnable(GL_TEXTURE_2D) # テクスチャマッピングを有効化
glBindTexture(GL_TEXTURE_2D, info.tex_name)
# スクロールオフセット値を得る
offs_y = 1.0 * @scrolls / SCROLLS_PER_STEP
dy = 0.2
dz = 1.5
0.upto(POINTS_Y - 2) do |y|
0.upto(POINTS_X - 2) do |x|
glBegin(GL_TRIANGLE_STRIP) # 三角ポリゴンを連続で描画
px0 = -0.5 + (x - 0.0) / (POINTS_X - 1)
px1 = -0.5 + (x + 1.0) / (POINTS_X - 1)
py0 = -0.5 + (y - 0.0 - offs_y) / (POINTS_Y - 2)
py1 = -0.5 + (y + 1.0 - offs_y) / (POINTS_Y - 2)
z = @height_map[y][x]
# glColor4d(1, 1, 1, z) # 透過度を指定してフォグに近い効果を出してる
glTexCoord2d(info.left, info.top) # テクスチャ座標を指定
# 頂点を指定
glVertex3d(py0, z * dy, px0 * dz)
z = @height_map[y + 1][x]
# glColor4d(1, 1, 1, z)
glTexCoord2d(info.left, info.bottom)
glVertex3d(py1, z * dy, px0 * dz)
z = @height_map[y][x + 1]
# glColor4d(1, 1, 1, z)
glTexCoord2d(info.right, info.top)
glVertex3d(py0, z * dy, px1 * dz)
z = @height_map[y+1][x + 1]
# glColor4d(1, 1, 1, z)
glTexCoord2d(info.right, info.bottom)
glVertex3d(py1, z * dy, px1 * dz)
glEnd
end
end
end
end
class MyWindow < Gosu::Window
# 初期化
def initialize
super WIDTH, HEIGHT
self.caption = "Ruby + Gosu + OpenGL Test" # ウインドウタイトルを指定
@gl_background = GLBackground.new
end
# 更新処理
def update
@gl_background.update
end
# 描画処理
def draw
@gl_background.draw(0)
end
end
MyWindow.new.show
テストで使った画像は以下。スクリプトと同じフォルダに置いておく。
こういう結果に。それっぽく描画されている、ような気がする。
gosu で opengl を使う手管は…。基本的には、gosu と gl を require して。
require 'gosu' require 'gl'
OpenGLで描画したい箇所で、
Gosu.gl(z値) { OpenGL描画処理をする関数 }
を呼べば、OpenGL で描画してくれる模様。この、Gosu.gl() は、OpenGLの描画が終わったら、その後gosuで描画できるように色々リセットしてくれるらしい。_Method: Gosu.gl - Documentation for gosu/gosu (master)
上記のドキュメントによると、注意事項として…。
- 「gosu自体は、OpenGL APIを提供してないから、OpenGLを使えるようにする何かと一緒に使ってね。例えば ruby-opengl と組み合わせて使うとか」
- 「Gosu.gl() の中で gosuの描画機能は使えないよ」
- 「Gosu.gl() は Gosu::Window の draw() の中で呼んでね」
また、 _GitHub - tjbladez/gosu-opengl-tutorials: Fun with opengl, gosu and ruby によると、もうちょっと違う書き方もできるのかもしれない。
_gosu-opengl-tutorials/lesson01.rb を眺めた感じでは、Gosu::Window を継承したクラスのdraw内で、
gl do ... ... ... endと書いて、そこで OpenGL 関係の処理を書いてある。手元で試してないので本当にその書き方で動くのかどうかは分からんけど、そういう書き方もあるっぽい、ってことで。
◎ gosu + opengl で3D描画の動作確認その2。 :
前述のソースを流用して、もうちょっと違う処理を書いてみた。
_gosu_opengl_test2.rb
使った画像は以下。
_mecha.png
こんな結果に。
手前のほうで、gosu を使ってSTGの自機だの敵だのを2D描画するだけでも、それっぽくなりそうな予感。
_gosu_opengl_test2.rb
# gosu + opengl の動作確認
# gosu-examplesの opengl_integration.rb を弄って、
# OpenGL 絡みの部分だけを列挙
# 円柱の中を進むイメージで描画
require 'gosu'
require 'gl'
WIDTH, HEIGHT = 640, 480
# OpenGLを使って背景描画するためのクラス
class GLBackground
# 初期化
def initialize
# テクスチャ読み込み
@image = Gosu::Image.new("mecha.png", :tileable => true)
@scrolls = 0
@rot_v = 0
@rot_v2 = 0
end
# 更新処理
def update
@scrolls += 1
@rot_v = (@rot_v + 0.3) % 360.0
@rot_v2 = (@rot_v2 + 0.5) % 360.0
if @scrolls == SCROLLS_PER_STEP
@scrolls = 0
end
end
# 描画処理
def draw(z)
# Gosu.gl(z値)でOpenGLの描画を行う
# 描画後、Gosuの描画ができるようにしてくれるらしい
Gosu.gl(z) { exec_gl }
end
private
include Gl
# Scrolling speed
SCROLLS_PER_STEP = 15
# OpenGL関係の処理
def exec_gl
glClearColor(0.0, 0.0, 0.0, 1.0) # 画面クリア色を指定 (r,g,b,a)
glClearDepth(1.0) # デプスバッファをクリア
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) # 画面クリア
# テクスチャ情報が取得できないなら何もせずに戻る
info = @image.gl_tex_info
return unless info
# 奥行き比較関数の種類を指定。デフォルトではGL_LESSが指定されてるらしい
# glDepthFunc(GL_GEQUAL)
glDepthFunc(GL_LESS)
glEnable(GL_DEPTH_TEST) # デプスバッファを使う
glEnable(GL_BLEND) # アルファブレンドを有効化
glMatrixMode(GL_PROJECTION) # 透視投影の設定
glLoadIdentity
glFrustum(-0.10, 0.10, -0.075, 0.075, 0.1, 100)
glMatrixMode(GL_MODELVIEW) # モデルビュー変換の指定
glLoadIdentity
glTranslate(0, 0.0, -0.8) # 位置をずらす
ry = 25.0 * Math.sin(@rot_v * Math::PI / 180.0)
glRotate(ry, 0.0, 1.0, 0.0) # 回転
rz = 20.0 * Math.sin(@rot_v2 * Math::PI / 180.0)
glRotate(rz, 0.0, 0.0, 1.0) # 回転
# スクロールオフセット値を得る
offs_y = 1.0 * @scrolls / SCROLLS_PER_STEP
glEnable(GL_TEXTURE_2D) # テクスチャマッピングを有効化
glBindTexture(GL_TEXTURE_2D, info.tex_name) # テクスチャを割り当て
# テクスチャの補間を指定
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
mx = 15.0
my = 1.2
mz = 1.2
ra = @rot_v * 4.0
lx = 28
0.upto(lx) do |bx|
px0 = (-0.5 + (bx - 0.0 - offs_y) / lx) * mx
px1 = (-0.5 + (bx + 0.6 - offs_y) / lx) * mx
aa = 15
0.step(360, aa) do |ang|
rad0 = (ang + ra) * Math::PI / 180.0
pz0 = Math.cos(rad0) * mz
py0 = Math.sin(rad0) * my
rad1 = (ang + ra + aa) * Math::PI / 180.0
pz1 = Math.cos(rad1) * mz
py1 = Math.sin(rad1) * my
glBegin(GL_TRIANGLE_STRIP)
glTexCoord2d(info.left, info.top)
glVertex3d(px0, py0, pz0)
glTexCoord2d(info.left, info.bottom)
glVertex3d(px0, py1, pz1)
glTexCoord2d(info.right, info.top)
glVertex3d(px1, py0, pz0)
glTexCoord2d(info.right, info.bottom)
glVertex3d(px1, py1, pz1)
glEnd
end
end
end
end
class MyWindow < Gosu::Window
# 初期化
def initialize
super WIDTH, HEIGHT
self.caption = "Ruby + Gosu + OpenGL Test" # ウインドウタイトルを指定
@gl_background = GLBackground.new
@bg_img = Gosu::Image.new("bg.png", :tileable => true)
end
# 更新処理
def update
@gl_background.update
end
# 描画処理
def draw
@gl_background.draw(2)
@bg_img.draw(0, 0, 0)
end
end
MyWindow.new.show
使った画像は以下。

こんな結果に。
手前のほうで、gosu を使ってSTGの自機だの敵だのを2D描画するだけでも、それっぽくなりそうな予感。
◎ OpenGL描画の後ろに何かを描画。 :
OpenGLで描画したソレの後ろに星空を表示したくてアレコレ試してたのだけど、どうやら OpenGLで描画した部分の後ろ・奥・背景に、gosuで何かを描画、てなことはできないっぽい。
どうやら、OpenGLで描画したソレは、全面が不透明になるようで。gosuの描画をz値指定で奥にしようとしてもOpenGL描画部分で上書きされてしまう、ような気がする。
つまり、OpenGLで描いた何かを、gosu描画の手前に持ってくることはできない ―― 背景は全部OpenGLで、手前はgosu描画で、という形にしかできない可能性が高いなと。もしかすると回避策・解決策があるのかもしれないけど、ちょっと見つけられなかった。
どうやら、OpenGLで描画したソレは、全面が不透明になるようで。gosuの描画をz値指定で奥にしようとしてもOpenGL描画部分で上書きされてしまう、ような気がする。
つまり、OpenGLで描いた何かを、gosu描画の手前に持ってくることはできない ―― 背景は全部OpenGLで、手前はgosu描画で、という形にしかできない可能性が高いなと。もしかすると回避策・解決策があるのかもしれないけど、ちょっと見つけられなかった。
[ ツッコむ ]
#2 [ruby] Ruby の OpenGL関係ライブラリは競合するのかも
Ruby上で OpenGL を使えるようにするライブラリはいくつかあるようだけど。
_opengl と _opengl-bindings をインストールしてみたら、どうやら競合するようで。というか opengl をインストールすると opengl-bindings 用のスクリプトが動作しない状態になる、というべきかしら。opengl-bindings だけを入れた状態なら、opengl-bindings 用のサンプルスクリプトがちゃんと動いた。
一応メモしておくけど、Ruby で OpenGL を使えるようにするライブラリの中で、メジャーなのは以下のような感じっぽい。たぶん。
_opengl-bindings | RubyGems.org | your community gem host
_GitHub - vaiorabbit/ruby-opengl: Yet another OpenGL wrapper for Ruby (and wrapper code generator).
_opengl | RubyGems.org | your community gem host
_GitHub - larskanis/opengl: The official repository of the ruby-opengl wrapper
_ruby-opengl | RubyGems.org | your community gem host
_RubyGems.org | your community gem host で、「opengl」で検索すると他にも色々と。
_opengl と _opengl-bindings をインストールしてみたら、どうやら競合するようで。というか opengl をインストールすると opengl-bindings 用のスクリプトが動作しない状態になる、というべきかしら。opengl-bindings だけを入れた状態なら、opengl-bindings 用のサンプルスクリプトがちゃんと動いた。
一応メモしておくけど、Ruby で OpenGL を使えるようにするライブラリの中で、メジャーなのは以下のような感じっぽい。たぶん。
- opengl-bindings ... Windowsの場合、別途 freeglut.dll か glfw3.dll を、スクリプトのあるフォルダにコピーしてやることで動作する。
- opengl ... C拡張(.so)が同梱されてるので、gem install opengl をするだけで OpenGL が使えるようになる。gosuと組み合わせて使うのはコレ。
- ruby-opengl ... Ruby 1.9 の頃は使われていたけど、今はメンテナンスされてないらしい。ソースコードを見ようとして github のページを開くと「openglのページを見てくれ」とだけ書いてあったりするので、どうやら「opengl を使ってほしい」ということになってるのかもしれない。
_opengl-bindings | RubyGems.org | your community gem host
_GitHub - vaiorabbit/ruby-opengl: Yet another OpenGL wrapper for Ruby (and wrapper code generator).
_opengl | RubyGems.org | your community gem host
_GitHub - larskanis/opengl: The official repository of the ruby-opengl wrapper
_ruby-opengl | RubyGems.org | your community gem host
_RubyGems.org | your community gem host で、「opengl」で検索すると他にも色々と。
[ ツッコむ ]
#3 [nitijyou] 日記をアップロードした
気が付いたら01/07を最後に日記をアップロードしてなかった…のでアップロード。
[ ツッコむ ]
以上、1 日分です。