apeescape2.com
  • メイン
  • プロジェクト管理
  • その他
  • アジャイルタレント
  • モバイルデザイン
技術

OpenGLの概要:3Dテキストレンダリングチュートリアル

DirectXやOpenGLなどのツールが利用できるようになった現在、3D要素をレンダリングするデスクトップアプリケーションを作成することはそれほど難しくありません。ただし、多くのテクノロジと同様に、開発者がこのニッチに参入することを困難にする障害が存在する場合があります。時間の経過とともに、DirectXとOpenGLの間の競争により、開発者はこれらのテクノロジにアクセスしやすくなり、ドキュメントが改善され、熟練したDirectXまたは OpenGL開発者 。

Microsoftによって導入および保守されているDirectXは、 Windowsプラットフォーム 。一方、 OpenGL は、KhronosGroupによって仕様が維持されている3Dグラフィックス分野向けのクロスプラットフォームAPIです。

openglの紹介



このOpenGLの紹介では、3Dテキストモデルをレンダリングするための非常に単純なアプリケーションを作成する方法を説明します。 Qt / Qt Creatorを使用してUIを実装し、このアプリケーションを複数のプラットフォームで簡単にコンパイルして実行できるようにします。この記事のために作成されたプロトタイプのソースコードは次のとおりです。 GitHubで入手可能 。

この単純なアプリケーションの目的は、3Dモデルを生成し、それらを単純な形式でファイルに保存し、画面上で開いてレンダリングすることです。レンダリングされたシーンの3Dモデルは回転可能でズーム可能であり、奥行きと寸法の感覚が向上します。

データ視覚化ツールの種類

前提条件

始める前に、このプロジェクトに役立ついくつかのツールを使用して開発環境を準備する必要があります。最初に必要なのは、Qtフレームワークと関連ユーティリティです。これらはからダウンロードできます。 www.qt.io 。オペレーティングシステムの標準パッケージマネージャーからも利用できる場合があります。その場合は、最初に試してみることをお勧めします。この記事では、Qtフレームワークにある程度精通している必要があります。ただし、フレームワークに精通していない場合でも、プロトタイプはフレームワークのかなり些細な機能に依存しているため、従うことを躊躇しないでください。

使用することもできます Microsoft Visual Studio 2013 Windowsの場合。その場合は、適切なものを使用していることを確認してください VisualStudio用のQtアドイン 。

この時点で、クローンを作成することをお勧めします GitHubのリポジトリ この記事を読みながら、それに従ってください。

OpenGLの概要

まず、単一のドキュメントウィジェットを使用して単純なQtアプリケーションプロジェクトを作成します。これは必要最低限​​のウィジェットであるため、コンパイルして実行しても有用なものは何も生成されません。 Qt Designerを使用して、「新規…」、「開く…」、「閉じる」、「終了」の4つの項目を含む「ファイル」メニューを追加します。これらのメニュー項目を対応するアクションにバインドするコードを見つけることができます リポジトリ内 。

「新規…」をクリックすると、次のようなダイアログがポップアップ表示されます。

openglポップアップ

ここで、ユーザーはテキストを入力し、フォントを選択し、結果のモデルの高さを微調整して、3Dモデルを生成することができます。 「作成」をクリックするとモデルが保存され、ユーザーが左下隅から適切なオプションを選択した場合はモデルも開く必要があります。お分かりのように、ここでの目標は、ユーザーが入力したテキストを3Dモデルに変換し、それをディスプレイにレンダリングすることです。

プロジェクトの構造は単純で、コンポーネントはいくつかのC ++ファイルとヘッダーファイルに分割されます。

c ++およびヘッダーファイル

createcharmodeldlg.h / cpp

ファイルには、QDialog派生オブジェクトが含まれています。これは、ユーザーがテキストを入力し、フォントを選択し、結果をファイルに保存するか、3Dで表示するかを選択できるダイアログウィジェットを実装します。

gl_widget.h / cpp

QOpenGLWidget派生オブジェクトの実装が含まれています。このウィジェットは、3Dシーンをレンダリングするために使用されます。

mainwindow.h / cpp

メインアプリケーションウィジェットの実装が含まれています。これらのファイルは、Qt Creatorウィザードによって作成されたため、変更されていません。

main.cpp

main(…)関数が含まれています。この関数は、メインアプリケーションウィジェットを作成して画面に表示します。

model2d_processing.h / cpp

2Dシーンの作成機能が含まれています。

model3d.h / cpp

3Dモデルオブジェクトを格納し、操作(保存、ロードなど)を可能にする構造が含まれています。

model_creator.h / cpp

3Dシーンモデルオブジェクトの作成を可能にするクラスの実装が含まれています。

OpenGLの実装

簡潔にするために、Qt Designerを使用したユーザーインターフェイスの実装の明らかな詳細、およびインタラクティブ要素の動作を定義するコードはスキップします。このプロトタイプアプリケーションには確かにいくつかの興味深い側面があります。これらは重要であるだけでなく、カバーしたい3Dモデルのエンコードとレンダリングにも関連しています。たとえば、このプロトタイプでテキストを3Dモデルに変換する最初のステップでは、テキストを2Dモノクロ画像に変換します。この画像が生成されると、画像のどのピクセルがテキストを形成し、どのピクセルが単に「空の」スペースであるかを知ることができます。 OpenGLを使用して基本的なテキストをレンダリングする簡単な方法がいくつかありますが、OpenGLを使用した3Dレンダリングの詳細をカバーするために、このアプローチを採用しています。

a * c ++

に この画像を生成する 、QImage :: Format_Monoフラグを使用してQImageオブジェクトをインスタンス化します。知っておく必要があるのは、テキストの一部であるピクセルとそうでないピクセルだけなので、モノクロ画像は問題なく機能するはずです。ユーザーがテキストを入力すると、このQImageオブジェクトが同期的に更新されます。フォントサイズと画像の幅に基づいて、ユーザー定義の高さ内にテキストが収まるように最善を尽くします。

次に、テキストの一部であるすべてのピクセル(この場合は黒いピクセル)を列挙します。ここでの各ピクセルは、個別の正方形のような単位として扱われます。これに基づいて、三角形のリストを生成し、それらの頂点の座標を計算して、3Dモデルファイルに保存できます。

独自の単純な3Dモデルファイル形式ができたので、レンダリングに集中できます。 OpenGLベースの3Dレンダリングの場合、QtはQOpenGLWidgetと呼ばれるウィジェットを提供します。このウィジェットを使用するには、次の3つの関数をオーバーライドできます。

  • initializeGl()-これは初期化コードが行くところです
  • paintGl()-このメソッドは、ウィジェットが再描画されるたびに呼び出されます
  • resizeGl(int w、int h)-このメソッドは、サイズが変更されるたびにウィジェットの幅と高さで呼び出されます

3dmodelファイル形式

initializeGlメソッドで適切なシェーダー構成を設定することにより、ウィジェットを初期化します。

glEnable(GL_DEPTH_TEST); glShadeModel(GL_FLAT); glDisable(GL_CULL_FACE);

最初の行は、他のピクセルの後ろにあり、見えないピクセルではなく、私たちに近いレンダリングされたピクセルのみをプログラムに表示させます。 2行目は、フラットシェーディング手法を指定しています。 3行目は、法線が指す方向に関係なく、プログラムに三角形をレンダリングさせます。

初期化されると、paintGlが呼び出されるたびにモデルをディスプレイにレンダリングします。 paintGlメソッドをオーバーライドする前に、バッファーを準備する必要があります。そのために、最初にバッファハンドルを作成します。次に、ハンドルをバインディングポイントの1つにバインドし、ソースデータをバッファーにコピーし、最後にプログラムにバッファーのバインドを解除するように指示します。

// Get the Qt object which allows to operate with buffers QOpenGLFunctions funcs(QOpenGLContext::currentContext()); // Create the buffer handle funcs.glGenBuffers(1, &handle); // Select buffer by its handle (so we’ll use this buffer // further) funcs.glBindBuffer(GL_ARRAY_BUFFER, handle); // Copy data into the buffer. Being copied, // source data is not used any more and can be released funcs.glBufferData(GL_ARRAY_BUFFER, size_in_bytes, src_data, GL_STATIC_DRAW); // Tell the program we’ve finished with the handle funcs.glBindBuffer(GL_ARRAY_BUFFER, 0);

オーバーライドするpaintGlメソッド内で、頂点の配列と正規データの配列を使用して、各フレームの三角形を描画します。

QOpenGLFunctions funcs(QOpenGLContext::currentContext()); // Vertex data glEnableClientState(GL_VERTEX_ARRAY);// Work with VERTEX buffer funcs.glBindBuffer(GL_ARRAY_BUFFER, m_hVertexes); // Use this one glVertexPointer(3, GL_FLOAT, 0, 0); // Data format funcs.glVertexAttribPointer(m_coordVertex, 3, GL_FLOAT, GL_FALSE, 0, 0); // Provide into shader program // Normal data glEnableClientState(GL_NORMAL_ARRAY);// Work with NORMAL buffer funcs.glBindBuffer(GL_ARRAY_BUFFER, m_hNormals);// Use this one glNormalPointer(GL_FLOAT, 0, 0); // Data format funcs.glEnableVertexAttribArray(m_coordNormal); // Shader attribute funcs.glVertexAttribPointer(m_coordNormal, 3, GL_FLOAT, GL_FALSE, 0, 0); // Provide into shader program // Draw frame glDrawArrays(GL_TRIANGLES, 0, (3 * m_model.GetTriangleCount())); // Rendering finished, buffers are not in use now funcs.glDisableVertexAttribArray(m_coordNormal); funcs.glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY);

パフォーマンスを向上させるために、プロトタイプアプリケーションでVertex Buffer Object(VBO)を使用しました。これにより、データをビデオメモリに保存し、レンダリングに直接使用できます。これに代わる方法として、レンダリングコードからデータ(頂点座標、法線、色)を提供します。

glBegin(GL_TRIANGLES); // Provide coordinates of triangle #1 glVertex3f( x[0], y[0], z[0]); glVertex3f( x[1], y[1], z[1]); glVertex3f( x[2], y[2], z[2]); // Provide coordinates of other triangles ... glEnd();

これはより簡単な解決策のように思えるかもしれません。ただし、これにはデータがビデオメモリバスを通過する必要があるため、パフォーマンスに深刻な影響があります。これは比較的遅いプロセスです。 paintGlメソッドを実装した後、シェーダーに注意を払う必要があります。

m_shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, QString::fromUtf8( '#version 400 ' ' ' 'layout (location = 0) in vec3 coordVertexes; ' 'layout (location = 1) in vec3 coordNormals; ' 'flat out float lightIntensity; ' ' ' 'uniform mat4 matrixVertex; ' 'uniform mat4 matrixNormal; ' ' ' 'void main() ' '{ ' ' gl_Position = matrixVertex * vec4(coordVertexes, 1.0); ' ' lightIntensity = abs((matrixNormal * vec4(coordNormals, 1.0)).z); ' '}')); m_shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, QString::fromUtf8( '#version 400 ' ' ' 'flat in float lightIntensity; ' ' ' 'layout (location = 0) out vec4 FragColor; ' 'uniform vec3 fragmentColor; ' ' ' 'void main() ' '{ ' ' FragColor = vec4(fragmentColor * lightIntensity, 1.0); ' '}')); m_shaderProgram.link(); m_shaderProgram.bind(); m_coordVertex = m_shaderProgram.attributeLocation(QString::fromUtf8('coordVertexes')); m_coordNormal = m_shaderProgram.attributeLocation(QString::fromUtf8('coordNormals')); m_matrixVertex = m_shaderProgram.uniformLocation(QString::fromUtf8('matrixVertex')); m_matrixNormal = m_shaderProgram.uniformLocation(QString::fromUtf8('matrixNormal')); m_colorFragment = m_shaderProgram.uniformLocation(QString::fromUtf8('fragmentColor'));

OpenGLでは、シェーダーは次のような言語を使用して実装されます。 GLSL 。この言語は、レンダリング前に3Dデータを簡単に操作できるように設計されています。ここでは、頂点シェーダーとフラグメントシェーダーの2つのシェーダーが必要になります。頂点シェーダーでは、変換行列を使用して座標を変換し、回転とズームを適用し、色を計算します。フラグメントシェーダーでは、フラグメントに色を割り当てます。次に、これらのシェーダープログラムをコンパイルして、コンテキストにリンクする必要があります。 OpenGLは、プログラム内のパラメータに外部からアクセスまたは割り当てることができるように、2つの環境をブリッジする簡単な方法を提供します。

C +を学ぶ方法
// Get model transformation matrix QMatrix4x4 matrixVertex; ... // Calculate the matrix here // Set Shader Program object' parameters m_shaderProgram.setUniformValue(m_matrixVertex, matrixVertex);

頂点シェーダーコードでは、元の頂点に変換行列を適用して、新しい頂点の位置を計算します。

gl_Position = matrixVertex * vec4(coordVertexes, 1.0);

この変換行列を計算するために、画面スケール、シーンの変換、スケール、回転、および中央揃えといういくつかの個別のマトリックスを計算します。次に、最終的な変換行列を計算するために、これらの行列の積を求めます。モデルの中心を原点(0、0、0)に変換することから始めます。これは、画面の中心でもあります。回転は、ポインティングデバイスを使用したユーザーのシーンとの相互作用によって決定されます。ユーザーはシーンをクリックし、ドラッグして回転させることができます。ユーザーがクリックすると、カーソル位置が保存され、移動後、2番目のカーソル位置が保存されます。これらの2つの座標をシーンの中心とともに使用して、三角形を形成します。いくつかの簡単な計算に従って、回転角を決定し、この変更を反映するように回転行列を更新できます。スケーリングについては、OpenGLウィジェットのX軸とY軸のスケーリング係数を変更するためにマウスホイールに依存するだけです。モデルは、シーンがレンダリングされる平面の背後に保持するために0.5だけ逆に変換されます。最後に、自然なアスペクト比を維持するために、長辺に沿ったモデル拡張の減少を調整する必要があります(OpenGLシーンとは異なり、レンダリングされるウィジェットは、いずれかの軸に沿って異なる物理的寸法を持つ場合があります)。これらすべてを組み合わせて、次のように最終的な変換行列を計算します。

void GlWidget::GetMatrixTransform(QMatrix4x4& matrixVertex, const Model3DEx& model) { matrixVertex.setToIdentity(); QMatrix4x4 matrixScaleScreen; double dimMin = static_cast(qMin(width(), height())); float scaleScreenVert = static_cast(dimMin / static_cast(height())); float scaleScreenHorz = static_cast(dimMin / static_cast(width())); matrixScaleScreen.scale(scaleScreenHorz, scaleScreenVert, 1.0f); QMatrix4x4 matrixCenter; float centerX, centerY, centerZ; model.GetCenter(centerX, centerY, centerZ); matrixCenter.translate(-centerX, -centerY, -centerZ); QMatrix4x4 matrixScale; float radius = 1.0; model.GetRadius(radius); float scale = static_cast(m_scaleCoeff / radius); matrixScale.scale(scale, scale, 0.5f / radius); QMatrix4x4 matrixTranslateScene; matrixTranslateScene.translate(0.0f, 0.0f, -0.5f); matrixVertex = matrixScaleScreen * matrixTranslateScene * matrixScale * m_matrixRotate * matrixCenter; }

結論

このOpenGL3Dレンダリングの概要では、udがビデオカードを利用して3Dモデルをレンダリングできるようにするテクノロジーの1つを探りました。これは、同じ目的でCPUサイクルを使用するよりもはるかに効率的です。非常に単純なシェーディング手法を使用し、マウスからのユーザー入力を処理することでシーンをインタラクティブにしました。ビデオメモリバスを使用して、ビデオメモリとプログラムの間でデータをやり取りすることは避けました。 1行のテキストを3Dでレンダリングしただけでも、より複雑なシーンは非常によく似た方法でレンダリングできます。

公平を期すために、このチュートリアルでは、3Dモデリングとレンダリングの表面をほとんど傷つけていません。これは広大なトピックであり、このOpenGLチュートリアルでは、3Dゲームやモデリングソフトウェアを構築するために知っておく必要があるのはこれだけだとは言えません。ただし、この記事の目的は、この領域を垣間見ることと、OpenGLを使用して3Dアプリケーションを簡単に構築できることを示すことです。

だまされないでください:従業員とコンサルタントの実際のコストを計算します

技術

だまされないでください:従業員とコンサルタントの実際のコストを計算します
運転資本の最適化:プロからの実用的なヒント

運転資本の最適化:プロからの実用的なヒント

財務プロセス

人気の投稿
BEM方法論の紹介
BEM方法論の紹介
Ember.js開発者が犯す8つの最も一般的な間違い
Ember.js開発者が犯す8つの最も一般的な間違い
ソフトウェア設計ドキュメントを書くことが重要な理由
ソフトウェア設計ドキュメントを書くことが重要な理由
初期市場参入の課題
初期市場参入の課題
AngularMaterialを使用して最新のWebアプリを構築する
AngularMaterialを使用して最新のWebアプリを構築する
 
モバイルエクスペリエンスのためのeコマースUX
モバイルエクスペリエンスのためのeコマースUX
コンサルタントツールボックス:あらゆるものを解決するためのフレームワーク
コンサルタントツールボックス:あらゆるものを解決するためのフレームワーク
モバイルWebアプリケーションの開発:いつ、なぜ、そしてどのように
モバイルWebアプリケーションの開発:いつ、なぜ、そしてどのように
トップピッチデッキの間違い
トップピッチデッキの間違い
GraphQLとREST-GraphQLチュートリアル
GraphQLとREST-GraphQLチュートリアル
人気の投稿
  • 物理エンジンの作り方
  • Visual StudioiOSアプリの開発
  • バックグラウンドでPythonを実行する
  • データマイニング用のTwitterデータセット
  • 視覚化の最も正確な定義は何ですか?
カテゴリー
プロジェクト管理 ヒントとツール モバイル 収益性と効率性 Uiデザイン Uxデザイン リモートの台頭 ライフスタイル プロセスとツール 人とチーム

© 2021 | 全著作権所有

apeescape2.com