blog

OpenGL- テクスチャと関連API

アーティストやプログラマーはテクスチャを好んで使います。テクスチャは、オブジェクトにディテールを追加するために使用できる2D画像です。テクスチャは、レンガが描かれた紙を3Dの家に継ぎ目なく折り曲げて、...

May 23, 2020 · 14 min. read
シェア

テクスチャとは何ですか?

アーティストやプログラマーはテクスチャを好んで使います。テクスチャは、オブジェクトにディテールを追加するために使用できる2Dイメージです。テクスチャは、レンガが描かれた紙のようなもので、シームレスに折りたたまれて3Dの家にはめ込まれ、家の外壁がレンガ壁のように見えると想像してください。1つのイメージに非常に多くのディテールを挿入できるので、頂点を追加指定しなくても、オブジェクトを非常に細かくすることができます。

イメージに加えて、テクスチャはシェーダに送信できる大量のデータを保存するために使用できますが、それは本題ではありません。

三角形にテクスチャをマッピングするには、テクスチャのどの部分が三角形の各頂点に対応するかを指定する必要があります。各頂点は、テクスチャイメージのどの部分からサンプリングするかを示すテクスチャ座標と関連付けられます。セグメント補間は、グラフの他のセグメントに対して実行されます。

テクスチャ座標はx軸とy軸上にあり、範囲は0から1です。テクスチャ座標を使ってテクスチャカラーを得ることをサンプリングと呼びます。テクスチャ座標はテクスチャイメージの左下隅から始まり、テクスチャイメージの右上隅で終わります。下のイメージは、テクスチャ座標が三角形にどのようにマッピングされるかを示しています。

三角形には3つのテクスチャ座標点を指定します。三角形の上部頂点はイメージの上部中央に対応するので、そのテクスチャ座標を設定し、同様に右下頂点も設定します。これらの3つのテクスチャ座標を頂点シェーダに渡すだけで、フラグメントシェーダに渡され、フラグメントシェーダが各フラグメントのテクスチャ座標を補間します。

テクスチャーの座標は次のようになります:

float texCoords[] = {
 0.0f, 0.0f, //  
 1.0f, 0.0f, //  
 0.5f, 1.0f //  
};

イメージの保存

  • イメージのサイズは、イメージそのものに直接関係します。

イメージの保存容量 = イメージの高さ * イメージの幅 * 1ピクセルあたりのバイト数

  • ピクセルの保存を変更・復元するAPIは以下の通りです:
void glPixelStorei(GLenum pname,GLint param);
void glPixelStoref(GLenum pname,GLfloat param);

パラメータ説明 pname: GL_UNPACK_ALIGNMENT OpenGLがデータバッファからイメージを展開する方法を指定します param: パラメータGL_UNPACK_ALIGNMENTで設定された値を示し、次のように設定できます 1: バイトアライメント 2: 偶数バイトのアライメント 4: ワードアライメント 8: ダブルバイト境界から始まる行

これらの2つの関数は、関数名の一方がiで終わり、もう一方がfで終わることを除けば、同じ目的を果たします。違いは2番目のパラメーターの型だけで、iはGLint、fはGLfloatです。

  • カラーバッファの内容をピクセルマップとして直接読み取るためのAPIは以下の通りです:
void glReadPixels(GLint x,GLint y,GLSizei width,GLSizei height, GLenum format, GLenum type,const void * pixels);

アルファ値は8ビット値の加重平均です:

テクスチャの読み込み

void glTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
void glTexImage3D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid *pixels);

関連パラメータ

  • Level: ロードされたミップマップのレベルを指定します。このパラメータは通常 0 に設定されます。
  • internalformat: 各テクスチャユニットに格納されるカラーコンポーネントの数。
  • width, height, depth parameters: ロードされたテクスチャの幅、高さ、深さ。注意! これらの値は2のべき乗の整数でなければなりません。
  • テクスチャマップのボーダー幅を指定できます。
  • formatパラメータ:ピクセルデータのデータ型
  • タイプのパラメータです:
  • type

テクスチャの更新

テクスチャイメージを更新することは、glTexImageを使用して新しいテクスチャを直接リロードするよりもはるかに高速であることがよくあります。これを行うために使用される関数は glTexSubImage で、これにも3つのバリエーションがあります。

void glTexSubImage1D(GLenum target,GLint level,GLint xOffset,GLsizei width,GLenum
 format,GLenum type,const GLvoid *data);
void glTexSubImage2D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLsizei
 width,GLsizei height,GLenum format,GLenum type,const GLvoid *data);
void glTexSubImage3D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLint
 zOffset,GLsizei width,GLsizei height,GLsizei depth,Glenum type,const GLvoid * data);

xOffset、yOffset、zOffset パラメータは、元のテクスチャマップ内のテクスチャデータの置き換えを開始するオフセットを指定します。 width、height**、depth` パラメータは、元のテクスチャに「挿入」される新しいテクスチャの幅、高さ、深さを指定します。width、height**、depth` パラメータは、元のテクスチャに「挿入」される新しいテクスチャの幅、高さ、深さを指定します。

置換テクスチャの挿入

以下の一連の関数は、カラーバッファからテクスチャを読み込み、元のテクスチャの一部を挿入または置き換えることができます。以下の一連の関数はすべて glCopyTexSubImage 関数のバリエーションです。

void glTexSubImage1D(GLenum target,GLint level,GLint xOffset,GLsizei width,GLenum
 format,GLenum type,const GLvoid *data);
void glTexSubImage2D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLsizei
 width,GLsizei height,GLenum format,GLenum type,const GLvoid *data);
void glTexSubImage3D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLint
 zOffset,GLsizei width,GLsizei height,GLsizei depth,Glenum type,const GLvoid * data);

注意:glCopyTexImage関数はありません。これは、カラーバッファが 2D であり、 3D テクスチャのソースとして 2D カラーイメージを使用する同等の方法がないためです。しかし、glCopyTexSubImage3D関数を使用して、カラーバッファのデータを3Dテクスチャで使用し、そのテクスチャプレーンの1つを設定することは可能です。

カラーバッファを使用してデータをロードし、新しいテクスチャを作成します。

1次元や2次元のテクスチャもカラーバッファからデータを読み込むことができます。カラーバッファからイメージを読み込み、新しいテクスチャとして使用するには、次の2つの関数を使用します。

void glCopyTexImage1D(GLenum target,GLint level,GLenum
 internalformt,GLint x,GLint y,GLsizei width,GLint border);
void glCopyTexImage2D(GLenum target,GLint level,GLenum
 internalformt,GLint x,GLint y,GLsizei width,GLsizei
 height,GLint border);

テクスチャオブジェクト

1) テクスチャオブジェクトの割り当てglGenTextures関数は、まず生成されたテクスチャの数を入力し、2番目のパラメータunsigned int配列に格納する必要があります。

void glGenTextures (GLsizei n, GLuint *textures);

2) テクスチャをバインドするテクスチャを作成した後、後続のテクスチャコマンドが現在バインドされているテクスチャを設定できるように、テクスチャをバインドする必要があります。

void glBindTexture (GLenum target, GLuint texture);

パラメータの説明

  • 対象: GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
  • targetアルファ値は8ビット値の加重平均です。_TEXTURE_1D _TEXTURE_2D _TEXTURE_3D

3) バインドされたテクスチャオブジェクトを削除します。

void glDeleteTextures (GLsizei n, const GLuint *textures);

パラメータの説明

  • n: テクスチャオブジェクト
  • n: テクスチャオブジェクト

5) テクスチャオブジェクトが有効かどうかのテストテクスチャがすでに領域が割り当てられているテクスチャオブジェクトの場合、この関数は GL_TRUEを返し、そうでない場合はGL_FALSEを返します。

GLboolean glIsTexture(GLuint texture)

テクスチャパラメータの設定

レンダリングのルールやテクスチャマップの動作に影響する多くのパラメータが適用されます。これらのテクスチャパラメータは、glTexParameter 関数の変数で設定します。

void glTexParameterf (GLenum target, GLenum pname, GLfloat param);
void glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params);
void glTexParameteri (GLenum target, GLenum pname, GLint param);
void glTexParameteriv (GLenum target, GLenum pname, const GLint *params);

パラメータの説明

  • ターゲットで、これらのパラメータが GL_TEXTURE_1D、GL_TEXTURE_2D、 GL_TEXTURE_3D などのどのテクスチャモードで使用されるかを指定します。
  • どのテクスチャパラメータを設定するかを指定します。
  • 特定のテクスチャパラメータの値を設定するために使用します。

アルファ値は8ビット値の加重平均です。

OpenGLのデフォルトの動作はテクスチャイメージを繰り返すことですが、OpenGLにはもっと多くのオプションがあります:

GL_REPEATテクスチャのデフォルト動作。テクスチャイメージを繰り返します。
gl_mirrored_repeatGL_REPEATと同じですが、各リピートイメージはImageで配置されます。
GL_CLAMP_TO_EDGEテクスチャ座標は0から1の間になるように制約され、余分な部分はテクスチャ座標のエッジを繰り返し、エッジが引き伸ばされたような効果を生み出します。
gl_clamp_to_border超過座標はユーザーが指定したエッジの色です。

各オプションは、テクスチャ座標がデフォルトの範囲外にあるときに出力される視覚効果が異なります。テクスチャイメージの例を見てみましょう:

(前述の各オプションは、glTexParameter関数を使用して別の軸に設定することができ、それらはx、y、zと同等です):

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);

最初のパラメータはテクスチャターゲットを指定します。2Dテクスチャが使用されるので、テクスチャターゲットはGL_TEXTURE_2Dです。 2番目のパラメータは、適用するテクスチャ軸で設定するオプションを指定する必要があります。意図する設定はWRAPオプションで、S軸とT軸を指定します。最後のパラメータはラッピングメソッドを渡す必要があり、この場合、OpenGLは現在アクティブなテクスチャのテクスチャラッピングメソッドをGL_MIRRORED_REPEATに設定します。

GL_CLAMP_TO_BORDERオプションが選択されている場合、エッジの色も指定する必要があります。GL_TEXTURE_BORDER_COLORこれは、glTexParameter関数のfv接尾辞形式を使用し、そのオプションとして使用し、エッジの色値としてfloat配列を渡すことによって行われます:

float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

テクスチャのフィルタリング方法

テクスチャ座標は解像度に依存せず、任意の浮動小数点値にすることができるので、OpenGLはテクスチャピクセルをテクスチャ座標にマッピングする方法を知っておく必要があります。これは、非常に大きなオブジェクトがあるのにテクスチャの解像度が低い場合に重要になります。お察しの通り、OpenGLにはテクスチャフィルタリングのオプションもあります。テクスチャフィルタリングには多くのオプションがありますが、ここでは最も重要な2つ、GL_NEARESTとGL_LINEARについて説明します。

GL_NEAREST は OpenGL のデフォルトのテクスチャフィルタです。GL_NEARESTに設定すると、OpenGLは中心点がテクスチャ座標に最も近いピクセルを選択します。下のイメージでは、プラス記号がテクスチャ座標を表す4つのピクセルが見えます。左上のテクスチャピクセルは、その中心点がテクスチャ座標に最も近いので、サンプルカラーとして選択されます:

GL_LINEARは、テクスチャ座標に近いテクスチャピクセルに基づいて補間を計算し、それらのテクスチャピクセル間の色を近似します。テクスチャピクセルの中心がテクスチャ座標に近ければ近いほど、そのテクスチャピクセルの色が最終的なサンプルの色に寄与します。下のイメージでは、返された色が隣接するピクセルの混合色であることがわかります:

では、この2種類のテクスチャフィルタリングの視覚効果はどのようなものでしょうか?低解像度のテクスチャを非常に大きなオブジェクトに適用するとどうなるか見てみましょう:

GL_NEAREST は、テクスチャを構成するピクセルがはっきりと見える粒状のパターンを生成し、GL_LINEAR は、個々のテクスチャピクセルが見えにくい滑らかなパターンを生成します。

テクスチャのフィルタリングオプションは、ズームインおよびズームアウト時に設定できます。たとえば、テクスチャがズームアウトされたときに近傍フィルタリングを使用し、ズームインされたときに線形フィルタリングを使用することができます。glTexParameter関数を使用して、ズームインとズームアウトのフィルタリング方法を指定する必要があります。このコードは、テクスチャのサラウンドメソッドを設定するのとよく似ています:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

マルチレベルフェージングテクスチャ

大きな部屋に何千ものオブジェクトがあり、それぞれにテクスチャが貼られているとします。オブジェクトのいくつかは遠くにありますが、それらのテクスチャは近くのオブジェクトと同じ高解像度を持っています。なぜなら、OpenGL は、テクスチャの大部分にまたがるフラグメントに対して、1つのテクスチャカラーだけをピックアップする必要があるからです。これは、小さなオブジェクトの非現実的な感触を作成し、それらのために高解像度のテクスチャを使用するメモリの浪費の問題は言うまでもありません。

OpenGLは、マルチレベル・フェージング・テクスチャ(multilevel fading textures)と呼ばれる概念を使用してこの問題を解決します。マルチレベル・フェージング・テクスチャの背後にある考え方は単純です:観察者からある閾値以上の距離に対して、OpenGLは異なるマルチレベル・フェージング・テクスチャを使用します。距離のため、低解像度はユーザーに気づかれません。また、マルチレベルフェージングテクスチャのもう1つの利点は、パフォーマンスが非常に良いことです。マルチレベルフェージングテクスチャがどのように見えるか見てみましょう:

幸いなことに、OpenGL には glGenerateMipmaps 関数があり、テクスチャを作成した後にこれを呼び出せば、あとはすべて OpenGL が処理してくれます。このチュートリアルの後半で、この関数の使い方を説明します。

レンダリングでマルチレベル・フェージング・テクスチャ・レベルを切り替えると、OpenGLはマルチレベル・フェージング・テクスチャ・レイヤーの2つの異なるレベル間で非現実的な硬い境界線を生成します。通常のテクスチャフィルタリングと同様に、多段階フェージングテクスチャのレベルを切り替えるときに、多段階フェージングの2つの異なるレベル間でNEARESTとLINEARフィルタリングを使用することもできます。異なるフェージングテクスチャレベル間のフィルタリング方法を指定するには、元のフィルタリング方法の代わりに、次の4つのオプションのいずれかを使用できます:

GL_NEARESTニアレストネイバーフィルタリングはMip基板上で実行されます。
GL_LINEARMipレベルで線形フィルタリングを実行します。
GL_NEAREST_MIPMAP_NEAREST最も近いマルチレベル・フェージング・テクスチャを使用してピクセル・サイズを一致させ、近傍補間を使用してテクスチャをサンプリングします。
GL_LINEAR_MIPMAP_NEAREST最も近い多段漸近テクスチャレベルを使用し、線形補間を使用してサンプリングします。
GL_NEAREST_MIPMAP_LINEAR近傍補間を用いてサンプリングされた、最も一致するピクセルサイズの2つのマルチレベル漸近テクスチャ間の線形補間
GL_LINEAR_MIPMAP_LINEAR隣接する2つのマルチレベル漸近テクスチャ間の線形補間を使用し、線形補間を使用してサンプリングします。

テクスチャフィルタリングと同様に、glTexParameteriを使用してフィルタリング方法を前述の4つの方法のうちの1つに設定することができます:

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

よくある間違いは、ズームフィルタオプションをマルチレベルフェージングテクスチャフィルタオプションの1つに設定することです。多段階フェージングテクスチャは主にテクスチャがスケールダウンされるときに使用されるため、これは何の効果もありません:テクスチャのスケーリングは多段階フェージングテクスチャを使用せず、スケーリングフィルタリングに多段階フェージングテクスチャオプションを設定すると GL_INVALID_ENUM エラーコードが生成されます。

圧縮テクスチャ

  • 圧縮テクスチャ形式を使用:
GL_COMPRESSED_RGBGL_RGB
圧縮γGL_RGBA
GL_COMPRESSED_SRGBGL_RGB
GL_COMPRESSED_SRGB_ALPHAGL_RGBA
圧縮赤GL_RED
GL_COMPRESSED_RGGL_RG
  • 圧縮の判断と選択
//選択された圧縮テクスチャ形式に応じて、最速、最適、自己選択アルゴリズムが圧縮形式を選択するために使用される。 
glHint(GL_TEXTURE_COMPRESSION_HINT,GL_FASTEST);
glHint(GL_TEXTURE_COMPRESSION_HINT,GL_NICEST);
glHint(GL_TEXTURE_COMPRESSION_HINT,GL_DONT_CARE);
  • 圧縮テクスチャの読み込み
void glCompressedTexImage1D(GLenum target,GLint level,GLenum internalFormat,GLsizei
 width,GLint border,GLsizei imageSize,void *data);
void glCompressedTexImage2D(GLenum target,GLint level,GLenum internalFormat,GLsizei
 width,GLint heigth,GLint border,GLsizei imageSize,void *data);
void glCompressedTexImage3D(GLenum target,GLint level,GLenum internalFormat,GLsizei
 width,GLsizei heigth,GLsizei depth,GLint border,GLsizei imageSize,void *data);

パラメータの説明

  • target:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D。
  • target:GL_TEXTURE_1D _TEXTURE_2D _TEXTURE_3D
  • internalformat:各テクスチャユニットに格納されるカラーコンポーネントの数。
  • width, height, depth パラメータ: ロードされたテクスチャの幅、高さ、深さ。== 注意!== これらの値は2の整数でなければなりません。
  • borderパラメータ:テクスチャマップのボーダー幅を指定できます。
  • format, type, data parameters: GlDrawPixels 関数と同じパラメータ。
  • glGetTexLevelParameter関数
GL_TEXTURE_COMPRESSEDテクスチャが圧縮されている場合は1を、そうでない場合は0を返します。
GL_TEXTURE_COMPRESSED_IMAGE_SIZE圧縮されたテクスチャのサイズ(バイト単位)
GL_TEXTURE_INTERNAL_FORMAT使用圧縮形式
GL_NUM_COMPRESSED_TEXTURE_FORMATSサポートされる圧縮テクスチャフォーマットの数
GL_COMPRESSED_TEXTURE_FORMATS定数値の配列で、それぞれがサポートされている圧縮テクスチャフォーマットの1つに対応しています。
GL_TEXTURE_COMPRESSION_HINT圧縮テクスチャヒントの値 (GL/NICEST/GL_FASTEST)
  • GL_EXT_texture_compression_s3tc圧縮形式
GL_COMPRESSED_RGB_S3TC_DXT1RGBデータは圧縮され、アルファ値は常に1.0です。
GL_COMPRESSED_RGBA_S3TC_DXT1RGBAデータは圧縮され、アルファ値は1.0または0.0を返します。
GL_COMPRESSED_RGAB_S3TC_DXT3RGB値は圧縮され、アルファ値は4ビットメモリに保存されます。
GL_COMPRESSED_RGBA_SETC_DXT5RGBデータは圧縮され、アルファ値は複数の8ビット値の加重平均です。
Read next

Redisの原理と使い方

実際、redisにおける文字列の実装はArrayListに似ているため、文字列の長さを取得する時間の複雑さはOです。 事前割り当ての戦略を使用して、拡張は2倍に拡張されますが、1MBより大きい場合は、拡張が1MBのみであるたびに拡張され、文字列の最大容量は512MBです。 ユーザの情報をキャッシュし、JSONを文字列にシリアライズし、それをredisに格納します。...

May 23, 2020 · 14 min read