Qt用のOpenGL ES 2.0ラッパー

むかしむかし、Android向けのゲームを書いていたとき、OpenGL ES 1.1を扱う必要がありました。 複雑なことは何もないようです。2Dグラフィック、PNG画像を描画する必要があり、スケーリング、回転、透明度の追加が可能です。 それから私はそれに一週間を費やしました、そしておそらくそれ以上、私は覚えていません。 OpenGLとは何の関係もなかったため、困難でした。 libgdxのソースコードは多くの助けになりました。ところで、すべての低レベルのOpenGL関数は開発者から隠されています。

時代は変わり、OpenGL ES 1.1はバージョン2.0に置き換えられていますが、これはまったく異なります。 それらがどのようなシェーダーであるのか、そしてなぜそれらがないのかを理解する必要があります。 これにも数日かかります。 2Dはすべてシンプルなので、簡単なはずです。 たとえば、QMLを使用する場合、これは次のように行われます。

Image { source: "brick.png" opacity: 0.8 rotation: 90 }
      
      





また、すべてをC ++で記述すると、OpenGLに慣れていない場合には理解が困難なコード行が多数得られます。 libgdxのようなOpenGLのラッパーであるQt専用のライブラリを見つけようとしましたが、役に立ちませんでした。 そのため、すべてがうまくいった後、すべてのOpenGL呼び出しを隠し、2Dグラフィックスを簡単に操作できる小さなラッパーを作成することにしました。



GitHubラッパーコード

GitHubのケーススタディ



アプリケーションでラッパーを使用するには、.proファイルに1行追加する必要があります。

 include (opengl-qt/opengl-qt.pri)
      
      





OpenGLQtからのアプリケーションウィンドウの継承::ウィジェット:

 class Widget : public OpenGLQt::Widget { public: Widget(); protected: virtual void drawSprites(); };
      
      





コンストラクターでファイルのパスとその中の画像の数を渡します。 タイマーを開始します。

 Widget::Widget() : OpenGLQt::Widget(10, "spritesheet.png") , m_counter(0) { startTimer(); }
      
      





drawSprites()メソッドをオーバーライドします。

 void Widget::drawSprites() { static Sprite apple = {86, 118, 30, 30}; //  ,    static Color color = {1, 1, 1, 1}; //   static DrawSpriteArgs args; args.sprite = apple; args.color = color; args.x = 10; //      args.y = 15; //     args.angle = 3.14f / 2.0f; //   90    args.scaleX = 0.5f; //   50%    args.scaleY = -1.0f; //      drawSprite(args); }
      
      





そしてそれだけです。 とても簡単ですよね? このラッパーを使用する場合は、すべてのグラフィックを1つのPNGファイルに入れる必要があります。 これは、たとえばTexturePackerを使用して実行できます。 これの意味は、パフォーマンスを向上させることです。テクスチャは、起動時に一度ビデオメモリにロードされ、プログラムの最後までそこに残ります。 イメージを描画する場合、このテクスチャでその座標を指定する必要があります。





OpenGLの詳細。 頂点シェーダー:

 uniform mat4 mvp_matrix; attribute vec4 a_position; attribute vec2 a_texcoord; attribute vec4 a_color; varying vec4 v_color; varying vec2 v_texcoord; void main() { gl_Position = mvp_matrix * a_position; v_texcoord = a_texcoord; v_color = a_color; }
      
      





フラグメントシェーダー:

 #ifdef GL_ES #define LOWP lowp precision mediump float; #else #define LOWP #endif varying vec2 v_texcoord; varying LOWP vec4 v_color; uniform sampler2D texture; void main() { gl_FragColor = v_color * texture2D(texture, v_texcoord); }
      
      





ほとんどのOpenGL関数は、プログラムの初期化中に1回呼び出されます。 その後、タイマーが開始され、1秒間に60回画面更新が行われます。

 void Widget::startTimer() { m_timer.start(1000.0f / 60.0f, this); } void Widget::timerEvent(QTimerEvent *) { updateGL(); } void Widget::paintGL() { beginDraw(); drawSprites(); endDraw(); } void Widget::beginDraw() { m_idx = 0; glClear(GL_COLOR_BUFFER_BIT); glClearColor(m_background.r, m_background.g, m_background.b, m_background.a); } void Widget::endDraw() { glDrawArrays(GL_TRIANGLES, 0, m_idx / 2); }
      
      





すべての描画はdrawSprites()メソッドで行われます。その例は上記にあります。 DrawSpriteArgs構造体に入力し、描画する必要のある各画像に対してdrawSpriteメソッドを呼び出すことで構成されます。 たとえば、画像を中心ではなく回転させるなど、標準的ではないものが必要な場合は、座標、テクスチャ、および色の配列を手動で入力できます。 配列の最大サイズは、コンストラクターでプログラムを起動するときに設定する必要があります。これは、QVectorが増加するとメモリの別の部分に移動でき、OpenGLにこれを通知する必要があるためです。

  int vertexLocation = m_program->attributeLocation("a_position"); m_program->enableAttributeArray(vertexLocation); glVertexAttribPointer(vertexLocation, 2, GL_FLOAT, GL_FALSE, 0, &m_verts[0]); int texcoordLocation = m_program->attributeLocation("a_texcoord"); m_program->enableAttributeArray(texcoordLocation); glVertexAttribPointer(texcoordLocation, 2, GL_FLOAT, GL_FALSE, 0, &m_texCoords[0]); int colorLocation = m_program->attributeLocation("a_color"); m_program->enableAttributeArray(colorLocation); glVertexAttribPointer(colorLocation, 4, GL_FLOAT, GL_FALSE, 0, &m_colors[0]);
      
      





射影行列はここから取得されました 。 ウィンドウのサイズ変更中に設定されます。

 void Widget::resizeGL(int w, int h) { glViewport(0, 0, w, h); QMatrix4x4 mat( 2.0f/w, 0, 0, -1, 0, 2.0f/h, 0, -1, 0, 0, -1, 0, 0, 0, 0, 1 ); m_program->setUniformValue("mvp_matrix", mat); }
      
      







それがおそらくすべてです。 本当にラッパーを使用したい人のために、例をコンパイルし、その仕組みを理解することを強くお勧めします。 コードはWindows 7(Qt 4.8 MinGW、MSVC 2008)、Mac OS X 10.8(Qt 5.1 Clang)、Nokia N9(Qt 4.7)、BlackBerry 10(Qt 4.8)でテストされ、どこでも正常に実行されます。



おわりに



私は同様の問題を抱えていただけでなく、この記事が誰かを助け、この小さなラッパーがプロジェクトでレンガになり、誰かの生活を楽にすることを願っています。 または、誰かがコードから何かを拾うかもしれません-お願いします。 私はOpenGLの専門家ではないため、実装にエラーがある可能性があります。 改善のための修正や提案がある場合は、コメントに自由に書いてください。



All Articles