Выбор цвета в openGL

Я пытался реализовать выбор цвета, и он просто не работает правильно. проблема в том, что если изначально покрасить мою модель в разные цвета, которые используются для выбора (я имею в виду, что я даю каждому треугольнику свой цвет, который является его цветом 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); дает мне неправильные значения .. и это сводит меня с ума! Кстати, основной функцией рендеринга является рендеринг (mesh m, boolean inPickingMode), как вы можете видеть, вы также можете видеть, что на модели есть текстура до щелчка мышью..


person gal    schedule 08.01.2012    source источник


Ответы (1)


есть несколько проблем с примером.

Во-первых, вы не очищаете буфер цвета и глубины при щелчке мышью (это приводит к тому, что сцена с цветными полигонами смешивается со сценой с текстурированными полигонами - и тогда это не работает). вам нужно позвонить:

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

Во-вторых, наверное, плохая идея использовать материалы при выборе цвета. Я не знаком с классом 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) по ней, что даст вам положение мыши в точке. ближней и дальней плоскости обзора, в пространстве предметов. Все, что вам нужно сделать, это вычесть их, чтобы получить направление луча (начало находится в ближней плоскости), и вы можете выбрать свои объекты, используя этот луч (пересечение гугл-луча и сферы).

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, чтобы вы могли видеть, что вы на самом деле рисуете на экране. Если вы видите текстуру или освещение, значит, что-то пошло не так.

person the swine    schedule 10.01.2012