1. ホーム
  2. opengl

[解決済み] glActiveTextureとglBindTextureの違いと関係

2022-05-10 21:54:58

質問

私が調べたところでは glActiveTexture はアクティブなquot;テクスチャユニット"を設定します。各テクスチャ ユニットは、複数のテクスチャ ターゲット(通常は GL_TEXTURE_1D、2D、3D または CUBE_MAP)を持つことができます。

私が正しく理解しているならば、あなたは glActiveTexture を呼び出して、まずテクスチャユニットを設定します(初期化は GL_TEXTURE0 を設定し、次にそのテクスチャユニットに(1つまたは複数の)"テクスチャターゲット"をバインドするのでしょうか?

利用可能なテクスチャユニットの数は、システム依存です。私のライブラリでは、最大 32 の列挙型があります。これは、本質的に、私の GPU の制限のうち小さい方 (私が考えるには 16 8)、および GPU メモリに一度に 32 個のテクスチャを持つことができるということでしょうか。GPU の最大メモリ (1 GB と思われる) を超えないという制限が追加されるのでしょう。

テクスチャ ターゲットとテクスチャ ユニットの関係は正しく理解されていますか。たとえば、私が 16 個のユニットと 4 個のターゲットを許可されているとすると、16*4=64 個のターゲットに余裕があるということでしょうか、それともそのように機能しないのでしょうか?

次に、一般的にテクスチャをロードしたいと思います。これは glTexImage2D . その最初の引数はテクスチャターゲットです。もし、この のように動作します。 glBufferData というように、テクスチャターゲットに "handle"/"texture name" を結合し、テクスチャデータをそのターゲットにロードして、間接的にそのハンドルと関連付けるのです。

についてはどうでしょうか。 glTexParameter ? テクスチャターゲットをバインドして、その同じターゲットを最初の引数として再び選択しなければならないのでしょうか?それとも、正しいアクティブなテクスチャユニットがある限り、テクスチャターゲットはバインドされる必要はないのでしょうか?

glGenerateMipmap は、ターゲットも操作します。そのターゲットは、成功するためにテクスチャ名にまだバインドされている必要がありますか?

では、テクスチャを貼ったオブジェクトを描画したい場合、次のようにすればよいのでしょうか。 両方とも アクティブなテクスチャ ユニットとテクスチャ ターゲットの両方を選択する必要がありますか? それとも、テクスチャユニットを選択し、そのユニットに関連付けられた 4 つのターゲットのいずれかからデータを取得するのでしょうか。これは、私を本当に混乱させる部分です。

どのように解決するのですか?

OpenGLオブジェクトのすべて

OpenGLオブジェクトの標準的なモデルは以下の通りです。

オブジェクトは状態を持ちます。それらを struct . ですから、次のようなオブジェクトが定義されているかもしれません。

struct Object
{
    int count;
    float opacity;
    char *name;
};

オブジェクトにはある値が格納されており、その値には 状態 . OpenGLオブジェクトも状態を持ちます。

状態の変更

C/C++では、もし型 Object のインスタンスがあった場合、以下のようにその状態を変更します。 obj.count = 5; オブジェクトのインスタンスを直接参照し、変更したい状態の特定の部分を取得し、そこに値を押し込むことになります。

OpenGLでは はしません。 を行います。

説明しない方が良いレガシーな理由のため、OpenGLオブジェクトの状態を変更するには、最初に バインド しなければなりません。これは glBind* の呼び出しで行われます。

これに相当するC/C++は次のようになります。

Object *g_objs[MAX_LOCATIONS] = {NULL};    
void BindObject(int loc, Object *obj)
{
  g_objs[loc] = obj;
}

テクスチャは興味深いもので、バインディングの特殊なケースを表しています。多くの場合 glBind* の呼び出しには、"target" というパラメータがあります。これは、そのタイプのオブジェクトをバインドすることができるOpenGLコンテキストの異なる場所を表します。例えば、フレームバッファオブジェクトを読み込むためにバインドすることができます ( GL_READ_FRAMEBUFFER ) または書き込み用 ( GL_DRAW_FRAMEBUFFER ). これはOpenGLがバッファをどのように使用するかに影響します。これは loc パラメータが表しています。

テクスチャが特別なのは 最初に をターゲットにバインドすると、特別な情報を取得するからです。テクスチャを最初に GL_TEXTURE_2D としてテクスチャを最初にバインドするとき、実際にはテクスチャに特別な状態を設定していることになります。つまり、このテクスチャは2Dテクスチャであるということです。そして、このテクスチャは 常に であり、この状態を変更することはできません。 常に . として最初にバインドされたテクスチャがある場合、そのテクスチャの状態を変更することはできません。 GL_TEXTURE_2D としてバインドされたテクスチャがある場合、そのテクスチャを 常に としてバインドします。 GL_TEXTURE_2D として結合しようとすると GL_TEXTURE_1D として結合しようとすると、(実行時に)エラーが発生します。

いったんオブジェクトがバインドされると、その状態を変更することができます。これは、そのオブジェクトに特化した汎用関数によって行われます。それらもまた、どのオブジェクトを変更するかを表す場所を取ります。

C/C++では、これは次のようになります。

void ObjectParameteri(int loc, ObjectParameters eParam, int value)
{
  if(g_objs[loc] == NULL)
    return;

  switch(eParam)
  {
    case OBJECT_COUNT:
      g_objs[loc]->count = value;
      break;
    case OBJECT_OPACITY:
      g_objs[loc]->opacity = (float)value;
      break;
    default:
      //INVALID_ENUM error
      break;
  }
}

この関数が、現在バインドされているものをどのように設定するかに注意してください。 loc の値を設定することに注意してください。

テクスチャオブジェクトの場合、主なテクスチャ状態変更関数は glTexParameter . テクスチャの状態を変更する他の関数は glTexImage 関数とそのバリエーション ( glCompressedTexImage , glCopyTexImage は、最近の glTexStorage ). 様々な SubImage のバージョンはテクスチャの内容を変更しますが、技術的にはその 状態 . そのため Image 関数はテクスチャストレージを割り当て、テクスチャのフォーマットを設定します。 SubImage 関数は単にピクセルをコピーするだけです。これはテクスチャの状態とはみなされません。

繰り返しになりますが、これらは だけです。 関数です。 glTexEnv は環境の状態を変更します。これはテクスチャオブジェクトに格納されているものには影響しません。

アクティブなテクスチャ

テクスチャの状況はより複雑ですが、これもレガシーな理由のため、公表されないままにしておくのが最善です。ここでは glActiveTexture が入ってきます。

テクスチャの場合、ターゲットだけでなく( GL_TEXTURE_1D , GL_TEXTURE_CUBE_MAP など)。また、テクスチャ ユニット . C/C++の例でいうと、こんな感じです。

Object *g_objs[MAX_OBJECTS][MAX_LOCATIONS] = {NULL};
int g_currObject = 0;

void BindObject(int loc, Object *obj)
{
  g_objs[g_currObject][loc] = obj;
}

void ActiveObject(int currObject)
{
  g_currObject = currObject;
}

今、私たちは2次元のリストである Object の 2 次元リストだけでなく、カレントオブジェクトの概念も持っていることに注意してください。現在のオブジェクトを設定する関数があり、現在のオブジェクトの最大数の概念があり、すべてのオブジェクト操作関数が現在のオブジェクトから選択されるように調整されています。

現在アクティブなオブジェクトを変更すると、ターゲットロケーションのセット全体が変更されます。したがって、現在のオブジェクト 0 に入る何かをバインドして、現在のオブジェクト 4 に切り替えると、まったく別のオブジェクトを変更することになります。

このテクスチャオブジェクトのアナロジーは完璧です...ほとんど。

見てください。 glActiveTexture は整数を取りません。 列挙子 . つまり、理論的には GL_TEXTURE0 から GL_TEXTURE31 . しかし、ひとつだけ理解しておかなければならないことがあります。

これは嘘だ!

実際に glActiveTexture が取ることのできる範囲は GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS . これは、実装が許容する同時マルチテクスチャの最大数です。これらはそれぞれ、異なるシェーダステージ用に異なるグループに分割されます。たとえば、GL 3.x クラスのハードウェアでは、16 のバーテックスシェーダテキス チャ、16 のフラグメントシェーダテキスチャ、および 16 のジオメトリシェーダテキスチャが得られます。したがって GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS は 48 になります。

しかし、48人の列挙者はいない。そのため glActiveTexture は実際には列挙体を取らないのです。その 正しい を呼び出す方法は glActiveTexture は以下のようになります。

glActiveTexture(GL_TEXTURE0 + i);

ここで i は0から GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS .

レンダリング

では、これらすべてがレンダリングとどのような関係があるのでしょうか。

シェーダーを使用する場合、サンプラーユニフォームをテクスチャイメージユニット( glUniform1i(samplerLoc, i) で、ここで i は画像単位)。で使用した数値を表します。 glActiveTexture . サンプラーは、サンプラーの種類に基づいてターゲットを選びます。そのため sampler2DGL_TEXTURE_2D のターゲットから選びます。これがサンプラーに異なるタイプがある理由の一つです。

さて、これは2つのGLSLサンプラーを持つことができるように怪しく聞こえますが、異なる タイプ で、同じテクスチャ画像ユニットを使用することができます。OpenGLはこれを禁じており、レンダリングしようとするとエラーが発生します。