web-dev-qa-db-ja.com

glActiveTextureとglBindTextureの違いと関係

私が収集したものから、glActiveTextureはアクティブな「テクスチャユニット」を設定します。各テクスチャユニットには、複数のテクスチャターゲット(通常は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のように動作する の場合、本質的に「ハンドル」/「テクスチャ名」をテクスチャターゲットにバインドし、テクスチャデータをそのターゲットにロードし、間接的に関連付けますそのハンドルで。

glTexParameterはどうですか?テクスチャターゲットをバインドして、最初の引数として同じターゲットを再度選択する必要がありますか?または、適切なアクティブテクスチャユニットがある限り、テクスチャターゲットをバインドする必要はありませんか?

glGenerateMipmapはターゲットでも動作します...ターゲットを成功させるには、まだターゲットをテクスチャ名にバインドする必要がありますか?

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

125
mpen

OpenGLオブジェクトについて

OpenGLオブジェクトの標準モデルは次のとおりです。

オブジェクトには状態があります。それらをstructと考えてください。そのため、次のように定義されたオブジェクトがあります。

_struct Object
{
    int count;
    float opacity;
    char *name;
};
_

オブジェクトには特定の値が格納されており、stateがあります。 OpenGLオブジェクトにも状態があります。

状態の変化

C/C++では、タイプObjectのインスタンスがある場合、その状態を次のように変更します。_obj.count = 5;_オブジェクトのインスタンスを直接参照し、必要な特定の状態を取得します変更し、それに値を押し込みます。

OpenGLでは、do n'tこれを行います。

レガシーの理由により、OpenGLオブジェクトの状態を変更するには、最初にbindコンテキストにそれを説明する必要があります。これは、_glBind*_呼び出しの一部で行われます。

これに相当するC/C++は次のとおりです。

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

テクスチャは面白いです。バインディングの特別なケースを表します。多くの_glBind*_呼び出しには、「ターゲット」パラメーターがあります。これは、そのタイプのオブジェクトをバインドできるOpenGLコンテキストのさまざまな場所を表します。たとえば、読み取り(_GL_READ_FRAMEBUFFER_)または書き込み(_GL_DRAW_FRAMEBUFFER_)のためにフレームバッファーオブジェクトをバインドできます。これは、OpenGLがバッファを使用する方法に影響します。これは、上記のlocパラメーターが表すものです。

テクスチャは、firstをターゲットにバインドすると特別な情報を取得するため、特別です。最初にテクスチャを_GL_TEXTURE_2D_としてバインドすると、実際にはテクスチャに特別な状態が設定されます。このテクスチャは2Dテクスチャであると言っています。そして、それはalways 2Dテクスチャになります。この状態は変更できませんever。最初に_GL_TEXTURE_2D_としてバインドされたテクスチャがある場合、alwaysを_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 関数とそのバリエーション( glCompressedTexImageglCopyTexImage 、最近の glTexStorage )。さまざまなSubImageバージョンはテクスチャの内容を変更しますが、技術的にはstateを変更しません。 Image関数は、テクスチャストレージを割り当て、テクスチャの形式を設定します。 SubImage関数は、ピクセルをコピーするだけです。テクスチャの状態とはみなされません。

繰り返してみましょう。これらは、テクスチャ状態を変更するonly関数です。 glTexEnvは環境の状態を変更します。テクスチャオブジェクトに保存されているものには影響しません。

アクティブテクスチャ

テクスチャの状況はより複雑です。これもレガシーの理由により、未公開のままにしておくのが最善です。これが glActiveTexture の出番です。

テクスチャの場合、ターゲット(_GL_TEXTURE_1D_、_GL_TEXTURE_CUBE_MAP_など)だけではありません。テクスチャもありますnits。 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;
}
_

現在、Objectsの2Dリストがあるだけでなく、現在のオブジェクトの概念もあります。現在のオブジェクトを設定する機能、現在のオブジェクトの最大数という概念があり、すべてのオブジェクト操作機能は現在のオブジェクトから選択するように調整されています。

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

テクスチャオブジェクトとのこの類推は完璧です...ほとんど。

glActiveTextureは整数を取りません。 enumeratorを取ります。これは、理論的には、_GL_TEXTURE0_から_GL_TEXTURE31_のすべてを使用できることを意味します。ただし、理解しなければならないことが1つあります。

THIS IS FALSE!

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

しかし、列挙子は48個ではありません。 glActiveTextureが実際に列挙子をとらないのはそのためです。 correctglActiveTextureを呼び出す方法は次のとおりです。

_glActiveTexture(GL_TEXTURE0 + i);
_

ここで、iは0から_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_までの数字です。

レンダリング

それでは、これらすべてがレンダリングと何の関係があるのでしょうか?

シェーダーを使用する場合、サンプラーのユニフォームをテクスチャ画像ユニットに設定します(glUniform1i(samplerLoc, i)、ここでiは画像ユニットです)。これは、glActiveTextureで使用した数値を表します。サンプラーは、サンプラータイプに基づいてターゲットを選択します。したがって、_sampler2D_は_GL_TEXTURE_2D_ターゲットから選択します。これが、サンプラーのタイプが異なる理由の1つです。

これは、同じテクスチャイメージユニットを使用するtypesが異なる2つのGLSLサンプラーを使用できるように思われます。しかし、できません。 OpenGLはこれを禁止しており、レンダリングしようとするとエラーが発生します。

242
Nicol Bolas

やってみよう!これらはすべてそれほど複雑なものではなく、単なる用語の問題です。明確にしたいと思います。


システムに利用可能なメモリがあるのとほぼ同じ数のTexture Objectsを作成できます。これらのオブジェクトは、glTexParameterによって提供されるパラメーターとともに、テクスチャの実際のデータ(テクセル)を保持します( [〜#〜] faq [〜#〜] を参照) )。

作成時には、1つのTexture Targetを1つのテクスチャオブジェクトに割り当てる必要があります。これは、テクスチャのタイプを表します(GL_TEXTURE_2DGL_TEXTURE_3DGL_TEXTURE_CUBE、。 ..)。

これらの2つの項目texture objectおよびtexture targetは、テクスチャデータを表します。後でそれらに戻ります。

テクスチャユニット

現在、OpenGLはtexture unitsの配列を提供し、描画中に同時に使用できます。配列のサイズはOpenGLシステムによって異なりますが、8があります。

bindテクスチャオブジェクトをテクスチャユニットに指定して、描画中に指定されたテクスチャを使用できます。

シンプルで簡単な世界では、与えられたテクスチャで描画するには、テクスチャオブジェクトをテクスチャユニットにバインドし、それを行います(擬似コード):

glTextureUnit[0] = textureObject

GLはステートマシンであるため、残念ながら、この方法では機能しません。textureObjectGL_TEXTURE_2Dテクスチャターゲットのデータを持っていると仮定すると、前の割り当てとして:

glActiveTexture(GL_TEXTURE0);                   // select slot 0 of the texture units array
glBindTexture(GL_TEXTURE_2D, textureObject);    // do the binding

GL_TEXTURE_2Dは、バインドするテクスチャのタイプに実際に依存することに注意してください。

テクスチャオブジェクト

擬似コードで、テクスチャデータまたはテクスチャパラメータを設定するには、たとえば次のようにします。

setTexData(textureObject, ...)
setTexParameter(textureObject, TEXTURE_MIN_FILTER, LINEAR)

OpenGLは、テクスチャオブジェクトを直接操作したり、コンテンツを更新/設定したり、パラメータを変更したりすることはできません。最初にアクティブなテクスチャユニットにバインドする必要があります(どちらか)。同等のコードは次のようになります。

glBindTexture(GL_TEXTURE_2D, textureObject)       // this 'installs' textureObject in texture unit
glTexImage2D(GL_TEXTURE_2D, ...)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

シェーダー

シェーダーはすべてのテクスチャユニットにアクセスできますが、アクティブなテクスチャは気にしません。

サンプラーのユニフォームは、サンプラーに使用するテクスチャユニットのインデックスを表すint値です(およびnot使用するテクスチャオブジェクト)。

そのため、テクスチャオブジェクトを使用するユニットにバインドする必要があります。

サンプラーのタイプは、テクスチャユニットで使用されるテクスチャターゲットと一致します:Sampler2D for GL_TEXTURE_2Dなど.

17
rotoglup

GPUをペイント処理プラントのように想像してください。

いくつかの塗装機に染料を届けるタンクがいくつかあります。塗装機では、染料がオブジェクトに適用されます。これらの戦車はテクスチャユニット

これらのタンクには、さまざまな種類の染料を装備できます。各種類の染料には、他の種類の溶媒が必要です。 「溶媒」はtexture targetです。便宜上、各タンクはいくつかの溶剤供給に接続されていますが、各タンクで一度に使用できる溶剤は1種類のみです。バルブ/スイッチがありますTEXTURE_CUBE_MAPTEXTURE_3DTEXTURE_2DTEXTURE_1D。すべての種類の染料を同時にタンクに入れることができますが、1種類の溶媒しか入っていないため、一致する種類の染料のみを「希釈」します。したがって、各種類のテクスチャをバインドできますが、「最も重要な」溶媒とのバインドは実際にタンクに入り、それが属する染料の種類と混合します。

そして、染料自体があります。それは倉庫から来て、それを「結合」することによってタンクに満たされます。それがあなたのテクスチャです。

12
datenwolf

シェーダーで2つのテクスチャからのルックアップが必要な場合:

uniform sampler2D tex1;  
uniform sampler2D tex2;  

tex1およびtex2のソースを次のように示す必要があります。

tex1 = gl.createTexture();  
gl.activeTexture(gl.TEXTURE3);  
gl.bindTexture(gl.TEXTURE_2D, tex1); 
gl.texParameteri(gl.TEXTURE_2D, ...);  
....


tex2 = gl.createTexture();  
gl.activeTexture(gl.TEXTURE7);  
gl.bindTexture(gl.TEXTURE_2D, tex2); 
gl.texParameteri(gl.TEXTURE_2D, ...);  
....  
var tex1Loc  = gl.getUniformLocation(your_shader,"tex1");  
var tex2Loc  = gl.getUniformLocation(your_shader,"tex2");

レンダーループ内:

gl.uniform1i(tex1Loc, 3);  
gl.uniform1i(tex2Loc, 7);  
// but you can dynamically change these values

Gl_bindtextureでは、そのようなことはできません。一方、レンダリングのループでバインドを使用する可能性があるのは、ストリーム(ビデオ、ウェブカメラ)のコンテンツでテクスチャをフィードする場合です。

gl.bindTexture(gl.TEXTURE_2D, tex1);  
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video);  
// in the render loop