サーチ…
テクスチャの基礎
テクスチャは、特定のデータエントリだけでなく、複数のエントリを混合(補間)するサンプルポイントにも便利なアクセスを可能にするデータストレージの一形態です。
OpenGLではテクスチャは多くのものに使用できますが、最も一般的には画像をポリゴン(たとえば三角形)にマッピングしています。テクスチャを三角形(または別のポリゴン)にマッピングするには、各頂点にテクスチャのどの部分が対応しているかを伝える必要があります。ポリゴンの各頂点にテクスチャ座標を割り当て、そのポリゴンのすべてのフラグメント間に補間します。テクスチャの座標は、通常、下の図に示すように、x軸とy軸の範囲は0〜1です。
この三角形のテクスチャ座標は次のようになります。
GLfloat texCoords[] = {
0.0f, 0.0f, // Lower-left corner
1.0f, 0.0f, // Lower-right corner
0.5f, 1.0f // Top-center corner
};
これらの座標をVBO(頂点バッファオブジェクト)に入れ、シェーダの新しい属性を作成します。頂点の位置には少なくとも1つの属性を既に持っていて、テクスチャ座標の別の属性を作成する必要があります。
テクスチャの生成
最初に行うことは、符号なしint テクスチャに格納されるIDによって参照されるテクスチャオブジェクトを生成することです。
GLuint texture;
glGenTextures(1, &texture);
その後、すべての後続のテクスチャコマンドがこのテクスチャを構成するようにバインドする必要があります。
glBindTexture(GL_TEXTURE_2D, texture);
画像を読み込む
イメージをロードするには、独自のイメージローダーを作成するか、Java の c ++またはTWLのPNGDecoderでSOIL (Simple OpenGL Image Library)などのイメージロードライブラリを使用できます。
SOILを使用してイメージをロードする例は次のようになります。
int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB);
これで、このイメージをテクスチャオブジェクトに割り当てることができます:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
その後、テクスチャオブジェクトのバインドを解除する必要があります。
glBindTexture(GL_TEXTURE_2D, 0);
テクスチャ座標のラップパラメータ
上で見たように、テクスチャの左下隅にはUV(st)座標(0,0)があり、テクスチャの右上隅には座標(1,1)がありますが、メッシュのテクスチャ座標は任意の範囲。これを処理するには、テクスチャ座標がどのようにテクスチャにラップされるかを定義する必要があります。
テクスチャ座標のラップパラメータは、 GL_TEXTURE_WRAP_S
、 GL_TEXTURE_WRAP_T
、およびGL_TEXTURE_WRAP_R
を使用してglTextureParameterで設定できます。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
可能なパラメータは次のとおりです。
GL_CLAMP_TO_EDGE
はテクスチャ座標を[1 / 2N、GL_CLAMP_TO_EDGE
/ 2N]の範囲にクランプする。ここでNは方向のテクスチャのサイズである。GL_CLAMP_TO_BORDER
同じしGL_CLAMP_TO_EDGE
が、クランプケースでは、フェッチされたテクセルデータがで指定された色で置換されてGL_TEXTURE_BORDER_COLOR
。GL_REPEAT
は、テクスチャ座標の整数部分を無視する。テクスチャがタイルされています。
-
GL_MIRRORED_REPEAT
:テクスチャ座標の整数部分が偶数の場合、それは無視されます。対照的に、テクスチャ座標の整数部分が奇数である場合、テクスチャ座標は1-frac(s)に設定される。 fract(s)はテクスチャ座標の小数部分です。これにより、2回ごとにテクスチャが反映されます。
-
GL_MIRROR_CLAMP_TO_EDGE
は、GL_CLAMP_TO_EDGEのようにクランプされる座標をテクスチャの1回のGL_MIRRORED_REPEAT
に対してGL_MIRRORED_REPEATのようにテクスチャ座標をGL_CLAMP_TO_EDGE
。
GL_TEXTURE_WRAP_S
、 GL_TEXTURE_WRAP_T
およびGL_TEXTURE_WRAP_R
のデフォルト値はGL_REPEAT
です。
テクスチャの適用
最後に行うことは、描画呼び出しの前にテクスチャをバインドすることです。
glBindTexture(GL_TEXTURE_2D, texture);
テクスチャとフレームバッファ
テクスチャ内のイメージをフレームバッファに添付することができます。これにより、そのテクスチャに直接レンダリングできます。
glGenFramebuffers (1, &framebuffer);
glBindFramebuffer (GL_FRAMEBUFFER, framebuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D,
texture,
0);
注:定義されていない動作を呼び出すため、同じレンダリングタスクで同じテクスチャから読み書きすることはできません。しかし、あなたはこのためにレンダリング呼び出しの間にglTextureBarrier()
使うことができます。
テクスチャデータを読み込む
関数glGetTexImage
テクスチャデータを読むことができます:
char *outBuffer = malloc(buf_size);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glGetTexImage(GL_TEXTURE_2D,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
outBuffer);
注:テクスチャの種類とフォーマットは一例であり、異なっていてもかまいません。
PBOの使用
あなたがするバッファをバインドする場合GL_PIXEL_UNPACK_BUFFER
その後、 data
内のパラメータglTexImage2D
そのバッファへのオフセットされます。
つまり、glTexImage2Dは、アプリケーションのメモリからすべてのデータがコピーされてから返されるのを待つ必要がなくなり、メインスレッドのオーバーヘッドが削減されます。
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, width*height*3, NULL, GL_STREAM_DRAW);
void* mappedBuffer = glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
//write data into the mapped buffer, possibly in another thread.
int width, height;
unsigned char* image = SOIL_load_image("image.png", &width, &height, 0, SOIL_LOAD_RGB);
memcpy(mappedBuffer, image, width*height*3);
SOIL_free_image(image);
// after reading is complete back on the main thread
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
しかし、PBOが本当に輝くのは、レンダリングの結果をアプリケーションメモリに読み込む必要がある場合です。それにバインドバッファに画素データを読み出すGL_PIXEL_PACK_BUFFER
その後のデータパラメータglGetTexImage
そのバッファにオフセットされます。
glGenBuffers(1, &pbo);
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
glBufferData(GL_PIXEL_PACK_BUFFER, buf_size, NULL, GL_STREAM_COPY);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glGetTexImage(GL_TEXTURE_2D,
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
null);
//ensure we don't try and read data before the transfer is complete
GLsync sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
// then regularly check for completion
GLint result;
glGetSynciv(sync, GL_SYNC_STATUS, sizeof(result), NULL, &result);
if(result == GL_SIGNALED){
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo);
void* mappedBuffer = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY);
//now mapped buffer contains the pixel data
glUnmapBuffer(GL_PIXEL_PACK_BUFFER);
}
GLSLシェーダでのテクスチャの使用
頂点シェーダはテクスチャ座標を頂点属性として受け付け、座標をフラグメントシェーダに転送します。デフォルトでは、フラグメントが三角形の位置に基づいて適切に補間された座標を受け取ることも保証されます:
layout (location = 0) in vec3 position;
layout (location = 1) in vec2 texCoordIn;
out vec2 texCoordOut;
void main()
{
gl_Position = vec4(position, 1.0f);
texCoordOut = texCoordIn;
}
フラグメントシェーダは、 texCoord
出力変数を入力変数として受け入れます。 uniform sampler2D
宣言することによって、フラグメントシェーダにテクスチャを追加することができます。テクスチャの断片をサンプリングするには、2つのパラメータを持つビルトイン関数texture
を使用します。最初にサンプルを取りたいテクスチャと、2番目のテクスチャはこのテクスチャの座標です。
in vec2 texCoordOut;
out vec4 color;
uniform sampler2D image;
void main()
{
color = texture(image, texCoordOut);
}
image
は直接テクスチャIDではありません。サンプリングされるテクスチャユニットの IDです。次に、テクスチャはプログラムに直接バインドされていません。テクスチャユニットにバインドされています。これは、最初にテクスチャユニットアクティブにすることによって達成さglActiveTexture
呼び出した後、およびglBindTexture
、この特定のテクスチャユニットに影響を与えます。しかし、デフォルトのテクスチャユニットはテクスチャユニット0
であるため、1つのテクスチャを使用するプログラムは、この呼び出しを省略すると簡単になります。