1

テクスチャのセクションが描画されたときにそれらをマスクするための最良の方法を見つけようとしています。私の問題は、私がアルファマスクを実行したように見えるという事実にあります!

openGLを使用して、カスタムビルドの2Dゲームエンジンを描画しています。ゲームは、スプライトと単純なブロックテクスチャで構成されています。

私の望ましい結果は次のようになります。

  • キャラクタースプライトが所定の位置に描画されます(単なるボックスではなく、アルファカラーを使用します)
  • アイテムがプレイヤーの手に引き込まれます(ボックスではなく、アルファカラーを使用してシーンに引き込まれます)
  • アイテムは、キャラクターの腕/手の後ろに表示されますが、体の残りの部分の上に表示されます。

今のところ、これを達成する方法を理解する唯一の方法は、それらを順番に(ボディ、アイテム、アーム)描画することですが、アートアセットを少し扱いやすくするために、これを避けたいと思います。私のアイデアの解決策は、キャラクターを描画してから、腕の「下」にあるはずのテクスチャの領域をブロックするアルファマスクを使用してアイテムを描画することです。

私が見た他の解決策はこのようなもので、glBlendFuncSeparate()関数が使用されています。私の現在のバージョンのOpenGLは拡張機能をサポートしていないため、拡張機能の導入を避けようとしています。私がその考えに反対していると言っているわけではありませんが、アルファマスクを描くためだけにそれを詰め込むのはちょっとした手間だと思いますか?

これは私にとって学習プロセスであることを完全に認めており、OpenGLがどのように処理されるかを実際に確認するための言い訳として使用しています。これを正しく描画するためにどこに向かうべきかについての提案はありますか?固定パイプラインのOpenGLがテクスチャを取得し、その上にアルファマスクを適用してから、それをバッファに描画する方法はありますか?キャラクターをあきらめて、モデルのいくつかの部分に分割する必要がありますか?

[更新:8/12/12]

Timが提案したコードを追加しようとしましたが、問題が発生しているようです。ステンシルバッファを有効にすると、必要なものだけでなく、すべてがブロックされます。これが私のテストサンプルコードです。

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

// Disable writing to any of the color fields
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

glStencilOp(GL_KEEP, GL_KEEP, GL_INCR); 

glStencilFunc(GL_ALWAYS, 0,0);

// Draw our blocking poly
glBegin(GL_POLYGON);                                   
    glVertex2f( 50,     50 );
    glVertex2f( 50,     50+128 );
    glVertex2f( 50+128, 50+128 );
glEnd();

glStencilFunc(GL_GREATER, 0, -1);

glEnable(GL_STENCIL_TEST);

// Re enable drawing of colors
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

// Enable use of textures
glEnable(GL_TEXTURE_2D);

// Bind desired texture for drawing
glBindTexture(GL_TEXTURE_2D,(&texture)[0]);

// Draw the box with colors
glBegin(GL_QUADS);                                   
    glTexCoord2d( 0, 0 );    glVertex2f( 50,     50 );
    glTexCoord2d( 0, 1 );    glVertex2f( 50,     50+128 );
    glTexCoord2d( 1, 1 );    glVertex2f( 50+128, 50+128 );
    glTexCoord2d( 1, 0 );    glVertex2f( 50+128, 50 );
glEnd();

// Swap buffers and display!
SDL_GL_SwapBuffers();

明確にするために、このシステムをセットアップするための私のinitコードもここにあります。

ステンシルを無効にしてコードを実行すると、次のようになります。glEnable(GL_STENCIL_TEST);なし

glEnable(GL_STENCIL_TEST)を使用すると、次のようになります。ここに画像の説明を入力してください

さまざまなオプションを試してみましたが、ステンシルバッファがすべてをブロックしている明確な理由がわかりません。

[更新#2 8/12/12]

動作するコードを取得しました。ありがとうございます。これが私が正しく動作するために実行することになったものです。

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

// Disable writing to any of the color fields
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);

glStencilOp(GL_INCR, GL_INCR, GL_INCR);

glEnable(GL_STENCIL_TEST);
// Draw our blocking poly
glBegin(GL_POLYGON);                                   
    glVertex2f( 50,     50 );
    glVertex2f( 50,     50+128 );
    glVertex2f( 50+128, 50+128 );
glEnd();

glStencilFunc(GL_EQUAL, 1, 1);

glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); 

// Re enable drawing of colors
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);

// Enable use of textures
glEnable(GL_TEXTURE_2D);

// Bind desired texture for drawing
glBindTexture(GL_TEXTURE_2D,(&texture)[0]);

// Draw the box with colors
glBegin(GL_QUADS);                                   
    glTexCoord2d( 0, 0 );    glVertex2f( 50,     50 );
    glTexCoord2d( 0, 1 );    glVertex2f( 50,     50+128 );
    glTexCoord2d( 1, 1 );    glVertex2f( 50+128, 50+128 );
    glTexCoord2d( 1, 0 );    glVertex2f( 50+128, 50 );
glEnd();
glDisable(GL_STENCIL_TEST);

// Swap buffers and display!
SDL_GL_SwapBuffers();
4

3 に答える 3

1

これが、1つのテクスチャと1つのアルファマスクがある状況についての私の考えです。

  1. 通常のようにシーンにキャラクターを描きます。
  2. RGBカラーチャンネルをロックして、で変更できないようにしますglColorMask
  3. でステンシルバッファを設定しますglStencilOp(GL_KEEP, GL_KEEP, GL_INCR); glStencilFunc(GL_ALWAYS, 0,0);
  4. アルファテストを有効にしてアルファマスクを描画します。これにより、アルファテストに合格した場所でステンシルバッファがインクリメントされます(マスクの極性に基づいてこれを反転する必要がある場合があります)
  5. この時点で、フレームバッファに文字テクスチャがあり、ステンシルバッファにマスクのアウトラインがあります。
  6. でカラーチャンネルを再度有効にしますglColorMask
  7. 武器のステンシルバッファを設定します。glStencilFunc(GL_GREATER, 0, -1);これにより、ステンシルバッファがゼロより大きい武器テクセルのみが描画され、ステンシルが更新されていないピクセルは拒否されます。
  8. 通常どおり武器のテクスチャを描画します。
于 2012-08-10T19:48:53.957 に答える
1

ティムは彼のコメントでかなり明確でしたが、私が最も直感的だと思う解決策をあなたに提示したいと思います。3Dなので、ちょっと待ってください...;)

基本的には、画像のZ座標を使用して、仮想の「レイヤー」を作成できます。その場合、どの順序でそれらを描画するかは重要ではありません。すべての画像を個別にアルファテストし、正しいZ値で描画するだけです。それでも不十分な場合は、すべてのピクセルの「深度」を含む個別のテクスチャを使用してから、2番目のテクスチャを使用して何らかの深度テストを実行できます。

glEnable(GL_DEPTH_TEST);このアプローチを使用する場合は、必ず電話してください。

于 2012-08-10T11:21:00.310 に答える
0

私が見ているように、問題は1つのテクスチャがあることですが、その一部は腕を表し、一部はキャラクターの残りの部分を表しています。問題は、キャラクターの上に武器を描きたいが、両方の上に腕を描きたいということです。

つまり、2つのオブジェクトを描画するときに、それらを3つの異なる「レイヤー」に配置する必要があります。これは基本的に意味がないので、あなたはちょっと立ち往生しています。

ただし、アイデアは次のとおりです。フラグメントプログラム(つまり、シェーダー)を使用します。

キャラクターのテクスチャのアルファチャネルをオーバーロードして、透明度とレイヤーの両方をエンコードすることをお勧めします。たとえば、0 =透明なボディ、64 =不透明なボディ、128 =透明なアーム、255=不透明なアームを使用します。

ここからオブジェクトを描画しますが、条件付きでオブジェクトの深さを3つのレイヤーに設定します。基本的に、キャラクターを2つの異なるレイヤーに描画するフラグメントプログラムを作成します。腕が前に引っ張られている間、キャラクターは後ろに押されます。武器が描画されると、シェーダーなしで描画されますが、キャラクターのピクセルの深さに対してテストされます。それはこのように機能します(明らかに、テストされていません)。

フラグメントプログラムを含むシェーダーmy_shaderを定義します。

uniform sampler2D character_texture;
void main(void) {
    vec4 sample = texture2D(character_texture,gl_TexCoord[0].st);

    int type; //Figure out what type of character texel we're looking at
    if      (fabs(sample.a-0.00)<0.01) type = 0; //transparent body
    else if (fabs(sample.a-0.25)<0.01) type = 1; //opaque body
    else if (fabs(sample.a-0.50)<0.01) type = 2; //transparent arm
    else if (fabs(sample.a-1.00)<0.01) type = 3; //opaque arm

    //Don't draw transparent pixels.
    if (type==0 || type==2) discard;

    gl_FragColor = vec4(sample.rgb,1.0);

    //Normally, you (can) write "gl_FragDepth = gl_FragCoord.z".  This
    //is how OpenGL will draw your weapon.  However, for the character,
    //we alter that so that the arm is closer and the body is farther.

    //Move body farther
    if      (type==1) gl_FragDepth = gl_FragCoord.z * 1.1;
    //Move arm closer
    else if (type==3) gl_FragDepth = gl_FragCoord.z * 0.9;
}

描画関数の擬似コードは次のとおりです。

//...

//Algorithm to draw your character
glUseProgram(my_shader);
glBindTexture(GL_TEXTURE_2D,character.texture.texture_gl_id);
glUniform1i(glGetUniformLocation(my_shader,"character_texture"),1);
character.draw();
glUseProgram(0);

//Draw your weapon
glEnable(GL_DEPTH_TEST);
character.weapon.draw();
glDisable(GL_DEPTH_TEST);

//...
于 2012-08-10T21:47:23.243 に答える