1

カラーピッキングを実装しようとしてきましたが、うまく機能しません。問題は、最初にピッキングに使用されるさまざまな色でモデルをペイントする場合 (つまり、各三角形に彼の ID カラーである異なる色を与える)、正常に動作することです (テクスチャなどなしで..)、しかしモデルのテクスチャを配置し、マウスをクリックすると、各三角形に異なる色を付けてモデルをペイントすると、機能しません..コードは次のとおりです。

public int selection(int x, int y) {        
    GL11.glDisable(GL11.GL_LIGHTING);
    GL11.glDisable(GL11.GL_TEXTURE_2D);

    IntBuffer viewport = BufferUtils.createIntBuffer(16); 
    ByteBuffer pixelbuff = BufferUtils.createByteBuffer(16);

    GL11.glGetInteger(GL11.GL_VIEWPORT, viewport);              

    this.render(this.mesh);

    GL11.glReadPixels(x, y, 1, 1, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, pixelbuff);

    for (int m = 0; m < 3; m++)
        System.out.println(pixelbuff.get(m));

   GL11.glEnable(GL11.GL_TEXTURE_2D);
   GL11.glEnable(GL11.GL_LIGHTING);

    return 0;
}


public void render(GL_Mesh m, boolean inPickingMode)
{
    GLMaterial[] materials = m.materials;   // loaded from the .mtl file
    GLMaterial mtl;
    GL_Triangle t;
    int currMtl = -1;
    int i = 0;

    // draw all triangles in object
    for (i=0; i < m.triangles.length; ) {
        t = m.triangles[i];

        // activate new material and texture
        currMtl = t.materialID;
        mtl = (materials != null && materials.length>0 && currMtl >= 0)? materials[currMtl] : defaultMtl;
        mtl.apply();
        GL11.glBindTexture(GL11.GL_TEXTURE_2D, mtl.textureHandle);

        // draw triangles until material changes
        for ( ; i < m.triangles.length && (t=m.triangles[i])!=null && currMtl == t.materialID; i++) {
                drawTriangle(t, i, inPickingMode);

        }
    }
}

private void drawTriangle(GL_Triangle t, int i, boolean inPickingMode) {

    if (inPickingMode) {
        byte[] triColor = this.triangleToColor(i);

        GL11.glColor3ub((byte)triColor[2], (byte)triColor[1], (byte)triColor[0]);
    }

    GL11.glBegin(GL11.GL_TRIANGLES);

    GL11.glTexCoord2f(t.uvw1.x, t.uvw1.y);
    GL11.glNormal3f(t.norm1.x, t.norm1.y, t.norm1.z);
    GL11.glVertex3f( (float)t.p1.pos.x, (float)t.p1.pos.y, (float)t.p1.pos.z);

    GL11.glTexCoord2f(t.uvw2.x, t.uvw2.y);
    GL11.glNormal3f(t.norm2.x, t.norm2.y, t.norm2.z);
    GL11.glVertex3f( (float)t.p2.pos.x, (float)t.p2.pos.y, (float)t.p2.pos.z);

    GL11.glTexCoord2f(t.uvw3.x, t.uvw3.y);
    GL11.glNormal3f(t.norm3.x, t.norm3.y, t.norm3.z);
    GL11.glVertex3f( (float)t.p3.pos.x, (float)t.p3.pos.y, (float)t.p3.pos.z);

    GL11.glEnd();
}

ご覧のとおり、マウスがクリックされるたびに呼び出される選択関数があります。次に、照明とテクスチャを無効にしてから、シーンを固有の色で再度レンダリングし、ピクセル バッファを読み取り、次の呼び出しを行います。 : GL11.glReadPixels(x, y, 1, 1, GL11.GL_RGB, GL11.GL_UNSIGNED_BYTE, pixelbuff); 私に間違った値を与えます..そしてそれは私を狂わせます!ところで、メインのレンダリング関数は render(mesh m, boolean inPickingMode) です。ご覧のとおり、マウスをクリックする前にモデルにテクスチャがあることもわかります..

4

1 に答える 1

2

この例にはいくつかの問題があります。

まず、マウスをクリックしたときにカラーと深度バッファをクリアしていません (これにより、カラー ポリゴンのあるシーンがテクスチャ ポリゴンのあるシーンに混ざり、機能しなくなります)。あなたが呼び出す必要があります:

GL11.glClear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);

第 2 に、色を選択するときにマテリアルを使用するのはおそらく悪い考えです。私はGLMaterialクラスに精通していませんが、GL_COLOR_MATERIALまたは照明が無効になっている場合でも、最終的な色を変更するその他のものを有効にする可能性があります。これを試して:

if(!inPickingMode) { // === add this line ===
    // activate new material and texture
    currMtl = t.materialID;
    mtl = (materials != null && materials.length>0 && currMtl >= 0)? materials[currMtl] : defaultMtl;
    mtl.apply();
    GL11.glBindTexture(GL11.GL_TEXTURE_2D, mtl.textureHandle);
} // === and this line ===

次に、色の選択とは関係ありませんが、正当な理由もなく glBegin() を頻繁に呼び出します。三角形の描画ループの前に、render() で呼び出すことができます (ただし、結果がどのように見えるかは変わりません)。

GL11.glBegin(GL11.GL_TRIANGLES);
// draw triangles until material changes
for ( ; i < m.triangles.length && (t=m.triangles[i])!=null && currMtl == t.materialID; i++) {
        drawTriangle(t, i, inPickingMode);
}
GL11.glEnd();

---今、私は元の質問を少し超えて答えています---

色の選択に関する問題は、レンダラーが色を表現するためのビット数が限られているため (チャネルごとにわずか 5 ビットなど)、これらのビットが設定されていない色を使用する必要があることです。モバイルデバイスでこれを行うのは悪い考えかもしれません。

オブジェクトが十分に単純な場合 (ピッキング用に球体などで表現できる場合)、オブジェクトのピッキングにレイトレーシングを使用することをお勧めします。それは非常に単純です。アイデアは、モデルビュー投影行列の逆を取り、それによってポイント (mouse_x, mouse_y, -1) と (mouse_x, mouse_y, +1) を変換することです。これにより、マウスの位置が得られますオブジェクト空間で、近くと遠くのビュー プレーンで。それらを差し引いて光線の方向を取得するだけで (原点は近い面にあります)、この光線を使用してオブジェクトを選択できます (Google 光線 - 球の交差)。

float[] mvp = new float[16]; // this is your modelview-projection
float mouse_x, mouse_y; // those are mouse coordinates (in -1 to +1 range)
// inputs

float[] mvp_inverse = new float[16];
Matrix.invertM(mvp_inverse, 0, mvp, 0);
// inverse the matrix

float nearX = mvp_inverse[0 * 4 + 0] * mouse_x +
              mvp_inverse[1 * 4 + 0] * mouse_y +
              mvp_inverse[2 * 4 + 0] * -1 +
              mvp_inverse[3 * 4 + 0];
float nearY = mvp_inverse[0 * 4 + 1] * mouse_x +
              mvp_inverse[1 * 4 + 1] * mouse_y +
              mvp_inverse[2 * 4 + 1] * -1 +
              mvp_inverse[3 * 4 + 1];
float nearZ = mvp_inverse[0 * 4 + 2] * mouse_x +
              mvp_inverse[1 * 4 + 2] * mouse_y +
              mvp_inverse[2 * 4 + 2] * -1 +
              mvp_inverse[3 * 4 + 2];
float nearW = mvp_inverse[0 * 4 + 3] * mouse_x +
              mvp_inverse[1 * 4 + 3] * mouse_y +
              mvp_inverse[2 * 4 + 3] * -1 +
              mvp_inverse[3 * 4 + 3];
// transform the near point

nearX /= nearW;
nearY /= nearW;
nearZ /= nearW;
// dehomogenize the coordinate

float farX = mvp_inverse[0 * 4 + 0] * mouse_x +
             mvp_inverse[1 * 4 + 0] * mouse_y +
             mvp_inverse[2 * 4 + 0] * +1 +
             mvp_inverse[3 * 4 + 0];
float farY = mvp_inverse[0 * 4 + 1] * mouse_x +
             mvp_inverse[1 * 4 + 1] * mouse_y +
             mvp_inverse[2 * 4 + 1] * +1 +
             mvp_inverse[3 * 4 + 1];
float farZ = mvp_inverse[0 * 4 + 2] * mouse_x +
             mvp_inverse[1 * 4 + 2] * mouse_y +
             mvp_inverse[2 * 4 + 2] * +1 +
             mvp_inverse[3 * 4 + 2];
float farW = mvp_inverse[0 * 4 + 3] * mouse_x +
             mvp_inverse[1 * 4 + 3] * mouse_y +
             mvp_inverse[2 * 4 + 3] * +1 +
             mvp_inverse[3 * 4 + 3];
// transform the far point

farX /= farW;
farY /= farW;
farZ /= farW;
// dehomogenize the coordinate

float rayX = farX - nearX, rayY = farY - nearY, rayZ = farZ - nearZ;
// ray direction

float orgX = nearX, orgY = nearY, orgZ = nearZ;
// ray origin

最後に - デバッグの提案: inPickingMode を true に設定してレンダリングを試み、実際に描画しているものを画面上で確認できるようにします。テクスチャまたはライティングが表示される場合は、何か問題が発生しています。

于 2012-01-10T17:50:14.560 に答える