1

vao idをRGBAにパックし、それを使用してオフスクリーンバッファーにレンダリングし、バッファーオブジェクトを使用して読み取ろうとすることで、オブジェクトピッキングを実装しようとしています。

テクスチャとzバッファRenderBufferオブジェクトを作成し、それらをFrameBufferオブジェクトにアタッチすることで、オフスクリーンバッファにレンダリングしています。

/* create a framebuffer object */ 
glGenFramebuffers(1, &fbo);     
/* attach the texture and the render buffer to the frame buffer */ 
glBindFramebuffer(GL_FRAMEBUFFER, fbo); 

/* generate a texture id */ 
glGenTextures(1, &tex); 
/* bind the texture */ 
glBindTexture(GL_TEXTURE_2D, tex); 
/* create the texture in the GPU */ 
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, WINDOW_SIZE_X, WINDOW_SIZE_Y 
    , 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); 

/* set texture parameters */ 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 

/* unbind the texture */ 
glBindTexture(GL_TEXTURE_2D, 0); 

/* create a renderbuffer object for the depth buffer */ 
glGenRenderbuffers(1, &rbo); 
/* bind the texture */ 
glBindRenderbuffer(GL_RENDERBUFFER, rbo); 
/* create the render buffer in the GPU */ 
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT 
    , WINDOW_SIZE_X, WINDOW_SIZE_Y); 

/* unbind the render buffer */ 
glBindRenderbuffer(GL_RENDERBUFFER, 0);


/* attach the texture and the render buffer to the frame buffer */ 
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, tex, 0); 
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT 
    , GL_RENDERBUFFER, rbo); 

// check the frame buffer 
if (glCheckFramebufferStatus( 
    GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
        std::cout << "Framebuffer status not complete" << '\n';
}
/* handle an error : frame buffer incomplete */ 
/* return to the default frame buffer */ 
glBindFramebuffer(GL_FRAMEBUFFER, 0); 

また、レンダリングが完了した後にFrameBufferから読み取るピクセルバッファーオブジェクトを生成します。

    /* generate the pixel buffer object */ 
glGenBuffers(1,&pbo);     
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo); 
glBufferData(GL_PIXEL_PACK_BUFFER, WINDOW_SIZE_X * WINDOW_SIZE_Y * 4, nullptr, GL_STREAM_READ); 
/* to avoid weird behaviour the first frame the data is loaded */ 
glReadPixels(0, 0, WINDOW_SIZE_X, WINDOW_SIZE_Y, GL_BGRA, GL_UNSIGNED_BYTE, 0);     

次に、レンダリングループでバインドし、画面外のFrameBufferにレンダリングします。

    GLubyte red, green, blue, alpha; 

/* bind the frame buffer */ 
glBindFramebuffer(GL_FRAMEBUFFER, fbo); 

/* clear the frame buffer */ 
glClearColor(0,0,0,0); 
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 

/* select the shader program */ 
glUseProgram(pickProgram); 
/* set the object color */ 

/*alpha = house.vaoId & 0xFF; 
blue = (house.vaoId >> 8) & 0xFF; 
green = (house.vaoId >> 16) & 0xFF; 
red = (house.vaoId >> 24) & 0xFF; */

GLuint objectId = 5;
alpha = objectId & 0xFF; 
blue  = (objectId >> 8) & 0xFF; 
green = (objectId >> 16) & 0xFF; 
red   = (objectId >> 24) & 0xFF; 

//Upload the packed RGBA values to the shader   
glUniform4f(baseColorUniformLocation, red, green ,blue, alpha);     

    //prepare to draw the object
pvm = projectionMatrix*viewMatrix*house.modelMatrix;
glUniformMatrix4fv(offScreenMatrixUniformLocation, 1, GL_FALSE, glm::value_ptr(pvm));

/* draw the object*/ 
glBindVertexArray(house.getVaoId());
glDrawRangeElements(GL_TRIANGLES,0,42,42,GL_UNSIGNED_SHORT,NULL);
glBindVertexArray(0);

//check that our framebuffer is ok
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
std::cout << "Framebuffer Error" << '\n';
}

GLuint temp;
    //get the object id from the read pixels
temp = get_object_id(); <--- this function is explained later


/* return to the default frame buffer */
glBindFramebuffer(GL_FRAMEBUFFER, 0); 

オフスクリーンバッファにレンダリングするフラグメントシェーダーは非常に単純です。

#version 420
uniform vec4 BaseColor; 
layout(location=0) out vec4 fragColor;

void main() 
{ 
 fragColor = BaseColor; 
} 

これは、オフスクリーンレンダリング中に呼び出され、パッケージ化されたRGBAをフレームバッファから抽出する関数です。

GLuint Engine::get_object_id() 
{ 
static int frame_event = 0; 
GLuint object_id; 
int x, y; 
GLuint red, green, blue, alpha, pixel_index; 
//GLuint read_pbo, map_pbo;
GLubyte* ptr; 

/* read one pixel buffer */ 
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo_a); 
/* map the other pixel buffer */  
    ///////////////////// NOTE :5th argument, BGRA or RGBA, doesn't make a difference right?
glReadPixels(0, 0, WINDOW_SIZE_X, WINDOW_SIZE_Y, GL_BGRA, GL_UNSIGNED_BYTE, 0);
ptr = (GLubyte*)glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_WRITE); 
/* get the mouse coordinates */ 
/* OpenGL has the {0,0} at the down-left corner of the screen */ 
glfwGetMousePos(&x, &y); 
y = WINDOW_SIZE_Y - y; 
object_id = -1; 
if (x >= 0 && x < WINDOW_SIZE_X && y >= 0 && y < WINDOW_SIZE_Y){ 
//////////////////////////////////////////
    //I have to admit I don't understand what he does here
///////////////////////////////////////////
    pixel_index = (x + y * WINDOW_SIZE_X) * 4; 
    blue = ptr[pixel_index]; 
    green = ptr[pixel_index + 1]; 
    red = ptr[pixel_index + 2]; 
    alpha = ptr[pixel_index + 3]; 

object_id = alpha +(red << 24) + (green << 16) + (blue << 8);
} 
glUnmapBuffer(GL_PIXEL_PACK_BUFFER); 
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); 
return object_id; 
} 

問題は、画面外のフレームバッファからピクセルを読み取り、vao_idを取得することになっているこのコードの最後のビットが、次の奇妙な動作をすることです。

RGBAにパックされた(シェーダーを介して送信された)4バイトのいずれかが0以外の場合、そのバイトはもう一方の端で0xFFとして出力されます。

だから私が送るなら

00000000 00000000 00000000 00000001 

私は取得します

00000000 00000000 00000000 11111111 

または私が送る場合

00000000 00010000 00000000 00000000 

私は取得します

00000000 11111111 00000000 00000000 

... get_object_id()でピクセルを読み取ったとき。

テクスチャをバインドして通常のFrameBufferでクワッドにレンダリングすると、オフスクリーンレンダリングに渡す色がクワッドで正しく表示されます。ただし、get_object_id()によって読み取られたピクセルにより、送信されるすべてのバイトが255(0xFF)に切り上げられます。だから私の推測では、その最終的な機能に問題があります。

4

1 に答える 1

2

フラグメントシェーダーは[0、1]の範囲の値を出力し、フレームバッファーに書き込まれると[0、255]に再マップされます。glUniform4f浮動小数点値を受け入れ、IDを[0、255]値ではなく[0、1]値として送信する必要があります。

glUniform4f(baseColorUniformLocation, red / 255.0f, green / 255.0f...);   
于 2012-04-12T12:35:06.323 に答える