私が収集したものから、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つのターゲットのいずれかからデータを取得できますか?これは本当に私を混乱させる部分です。
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
関数とそのバリエーション( glCompressedTexImage
、 glCopyTexImage
、最近の 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;
}
_
現在、Object
sの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はこれを禁止しており、レンダリングしようとするとエラーが発生します。
やってみよう!これらはすべてそれほど複雑なものではなく、単なる用語の問題です。明確にしたいと思います。
システムに利用可能なメモリがあるのとほぼ同じ数のTexture Objectsを作成できます。これらのオブジェクトは、glTexParameterによって提供されるパラメーターとともに、テクスチャの実際のデータ(テクセル)を保持します( [〜#〜] faq [〜#〜] を参照) )。
作成時には、1つのTexture Targetを1つのテクスチャオブジェクトに割り当てる必要があります。これは、テクスチャのタイプを表します(GL_TEXTURE_2D
、GL_TEXTURE_3D
、GL_TEXTURE_CUBE
、。 ..)。
これらの2つの項目texture objectおよびtexture targetは、テクスチャデータを表します。後でそれらに戻ります。
テクスチャユニット
現在、OpenGLはtexture unitsの配列を提供し、描画中に同時に使用できます。配列のサイズはOpenGLシステムによって異なりますが、8があります。
bindテクスチャオブジェクトをテクスチャユニットに指定して、描画中に指定されたテクスチャを使用できます。
シンプルで簡単な世界では、与えられたテクスチャで描画するには、テクスチャオブジェクトをテクスチャユニットにバインドし、それを行います(擬似コード):
glTextureUnit[0] = textureObject
GLはステートマシンであるため、残念ながら、この方法では機能しません。textureObject
がGL_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
など.
GPUをペイント処理プラントのように想像してください。
いくつかの塗装機に染料を届けるタンクがいくつかあります。塗装機では、染料がオブジェクトに適用されます。これらの戦車はテクスチャユニット
これらのタンクには、さまざまな種類の染料を装備できます。各種類の染料には、他の種類の溶媒が必要です。 「溶媒」はtexture targetです。便宜上、各タンクはいくつかの溶剤供給に接続されていますが、各タンクで一度に使用できる溶剤は1種類のみです。バルブ/スイッチがありますTEXTURE_CUBE_MAP
、TEXTURE_3D
、TEXTURE_2D
、TEXTURE_1D
。すべての種類の染料を同時にタンクに入れることができますが、1種類の溶媒しか入っていないため、一致する種類の染料のみを「希釈」します。したがって、各種類のテクスチャをバインドできますが、「最も重要な」溶媒とのバインドは実際にタンクに入り、それが属する染料の種類と混合します。
そして、染料自体があります。それは倉庫から来て、それを「結合」することによってタンクに満たされます。それがあなたのテクスチャです。
シェーダーで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