Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ glGetPixels屏幕外帧缓冲区opengl_C++_Opengl - Fatal编程技术网

C++ glGetPixels屏幕外帧缓冲区opengl

C++ glGetPixels屏幕外帧缓冲区opengl,c++,opengl,C++,Opengl,我在我的程序中生成了一个点云,现在,我希望能够单击这个点云中的一个点,该点云使用OpenGL渲染到我的屏幕上 为了做到这一点,我使用了一种技巧,即在屏幕外渲染时根据VBO中的索引为每个像素提供一种颜色。我使用相同的相机进行屏幕外渲染和屏幕上渲染,以便它们一起移动,当我单击时,我会获取屏幕外渲染的值,以检索VBO中的位置,以获取我单击的点。这是理论,因为当我点击时,我只有(0,0,0)。我相信这意味着我的FBO不是很好,但我不确定是否是这样,或者问题是否来自其他地方 下面是步骤clicFBO是我用

我在我的程序中生成了一个点云,现在,我希望能够单击这个点云中的一个点,该点云使用OpenGL渲染到我的屏幕上

为了做到这一点,我使用了一种技巧,即在屏幕外渲染时根据VBO中的索引为每个像素提供一种颜色。我使用相同的相机进行屏幕外渲染和屏幕上渲染,以便它们一起移动,当我单击时,我会获取屏幕外渲染的值,以检索VBO中的位置,以获取我单击的点。这是理论,因为当我点击时,我只有(0,0,0)。我相信这意味着我的FBO不是很好,但我不确定是否是这样,或者问题是否来自其他地方

下面是步骤
clicFBO
是我用于屏幕外渲染的FBO,而
clicTextureColorBuf
是我在FBO中写入的纹理

glGenFramebuffers(1, &clicFBO);
glBindFramebuffer(GL_FRAMEBUFFER, clicFBO);
glGenTextures(1, &clicTextureColorBuf);
glBindTexture(GL_TEXTURE_2D, clicTextureColorBuf);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, clicTextureColorBuf, 0);
GLenum DrawBuffers[1] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, DrawBuffers);
在那之后,我写了一个着色器,在VBO中为每个点提供其索引的颜色

std::vector<cv::Point3f> reconstruction3D; //Will contain the position of my points
std::vector<float> indicesPointsVBO; //Will contain the indexes of each point
for (int i = 0; i < pts3d.size(); ++i) {
    reconstruction3D.push_back(pts3d[i].pt3d);
    colors3D.push_back(pt_tmp);
    indicesPointsVBO.push_back(((float)i / (float)pts3d.size() ));
}

GLuint clicVAO, clicVBO[2];
glGenVertexArrays(1, &clicVAO);
glGenBuffers(2, &clicVBO[0]);
glBindVertexArray(clicVAO);
glBindBuffer(GL_ARRAY_BUFFER, clicVBO[0]);
glBufferData(GL_ARRAY_BUFFER, reconstruction3D.size() * sizeof(cv::Point3f), &reconstruction3D[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glEnable(GL_PROGRAM_POINT_SIZE);

glBindBuffer(GL_ARRAY_BUFFER, clicVBO[1]);
glBufferData(GL_ARRAY_BUFFER, indicesPointsVBO.size() * sizeof(float), &indicesPointsVBO[0], GL_STATIC_DRAW);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, 0, (GLvoid*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
片段:

#version 330 core
layout(location = 0) out vec4 FragColor;
in float Col;
void main()
{
    FragColor = vec4(Col, Col, Col ,1.0);
}
我就是这样渲染这个纹理的:

    glm::mat4 view = camera.GetViewMatrix();
    glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 1.0f, 100.0f);
    glBindFramebuffer(GL_FRAMEBUFFER, clicFBO);
    clicShader.use();

    glDisable(GL_DEPTH_TEST);
    glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    clicShader.setMat4("projection", projection);
    clicShader.setMat4("view", view);
     model = glm::mat4();
    clicShader.setMat4("model", model);
    clicShader.setInt("pointSize", pointSize);

    glBindVertexArray(clicVAO);
    glDrawArrays(GL_POINTS, 0, (GLsizei)reconstruction3D.size());
    glBindFramebuffer(GL_FRAMEBUFFER, 0);
然后,当我单击时,我使用以下代码:

glBindFramebuffer(GL_FRAMEBUFFER, clicFBO);
glReadBuffer(GL_COLOR_ATTACHMENT0);
int width = 11, height = 11;
std::array<GLfloat, 363> arry{ 1 };

glReadPixels(Xpos - 5, Ypos - 5, width, height, GL_RGB, GL_UNSIGNED_BYTE, &arry);
for (int i = 0; i < 363; i+=3) { // It's 3 time the same number anyways for each number
    std::cout << arry[i] << " "; // It gives me only 0's
}
std::cout << std::endl << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, clicFBO);
glBindFramebuffer(GL_FRAMEBUFFER,clicFBO);
glReadBuffer(GL_COLOR_ATTACHMENT0);
内部宽度=11,高度=11;
std::数组arry{1};
glReadPixels(Xpos-5、Ypos-5、宽度、高度、GL_RGB、GL_无符号字节和arry);
对于(inti=0;i<363;i+=3){//对于每个数字,它是相同数字的3倍

std::cout使用帧缓冲区对象存储“对象标识符”是一种很酷的方法。但也希望看到对象,对吗?然后还必须渲染到默认帧缓冲区(我称之为“defFB”,它不是FBO)

由于需要渲染到两个不同的目标,因此需要以下技术之一:

  • 绘制对象两次(例如,使用两个
    gldrawArray
    调用),一个到FBO,另一个到defFB
  • 一次绘制两个FBO的图像,然后将其中一个(带颜色)blit到defFB
对于第一种技术,您可以使用附加到FBO的纹理(就像您当前所做的那样),也可以使用“Renderbuffer”并对其进行绘制

第二种方法需要片段着色器中的第二个“out”:

layout(location = 0) out vec3 color; //GL_COLOR_ATTACHMENT0
layout(location = 1) out vec3 objID; //GL_COLOR_ATTACHMENT1
并使用
glDrawBuffers
设置两个附件

对于blit部分,请阅读

请注意,在本例中,两个“out”具有相同的格式,
vec3

代码中的失败是设置了
RGB
纹理格式,并在
glReadPixels
中使用此格式,但FS中的“out”是
vec4
而不是
vec3

更多的关注是:

  • 检查完整性与否
  • 可能需要在FBO上使用“深度附件”,即使它不用于读取
  • 禁用深度测试会将所有元素放入框架中。点拾取将选择最后绘制的,而不是最近绘制的
    • 我发现了问题。
      我的代码中有两个失败:
      第一个是,在OpenGL中,图像和帧缓冲区之间存在Y反转。因此,为了选择好的点,必须使用视口的大小翻转Y:我这样做:

      GLint m_viewport[4];
      glGetIntegerv(GL_VIEWPORT, m_viewport);
      int YposTMP = m_viewport[3] - Ypos - 1;
      
      第二个是使用
      glReadPixels(Xpos-2,Ypos-2,宽度,高度,GL_RGB,GL_无符号字节,&pixels[0]);
      ,第六个参数必须是
      GL_FLOAT
      ,因为我返回的数据是FLOAT

      谢谢大家!
      致以最诚挚的问候,

      R.S

      我曾经做过类似的事情,我不记得我明确地将其设置为“屏幕外”。我只是使用了一个不同的FBO,我称之为pickmap。我在谷歌上搜索了一下,发现了这个教程:。顺便说一句。同时,我们踢了这项技术。因为它太慢了。(相反,我们在CPU端进行交叉测试。)有趣的是,教程中也提到了这个弱点:它可能会导致明显的帧率下降,是的,我可以证实。嗨!谢谢!我会看一看!要做交叉测试,我应该使用八叉树等创建一个数据结构。因为我做了很多计算,我只想看到数据,所以FPS下降不会太麻烦事实上,g是我的。再次感谢!在我们的例子中,我们有分组(实体)的三角形汤。数据量是可以调用的。(CPU不能像GPU那样提供大量并行化。)因此,大多数情况下需要某种分支和边界。如果数据存储在经典场景图中(带边界球体),这是可以利用的。在您的情况下,oct树可能是一种足够的方法。其余的是3d数学。当您使用
      glm
      ,大多数需要的函数可能都在那里,或者可以构建在顶部。我已经为另一个项目使用glm构建了一个八叉树。第二种方法是使用glUnproject 2次,在未投影的2个点之间创建一条光线,然后用八叉树看看哪个点离这条射线更近,对吗?因为我认为我现在使用的方法真的很接近,所以我想完成。如果我真的找不到方法,我会做另一个(如果我有太多问题,我会尝试新方法)但现在,我将坚持解决我的错误^ ^关于光线投射,对于点,我做的有点不同:我检查点对截锥(截锥状视锥)。优点:我可以使用相同的测试选择和橡皮筋选择。(与距离无关)点大小。(这与我使用
      glPointSize()
      )的渲染非常匹配。顺便说一句,从视锥体和l、r、t、b(通常用于定义视锥体的6个参数中的4个)的一些附加缩放来定义此拾取视锥体非常容易,也就是说,我不需要
      glUnproject()
      .Mmmmh,谢谢你的回答,但实际上,我使用默认帧缓冲区进行渲染。我可以有效地看到我想要看到的内容,我的问题只出现在屏幕外渲染上。我已经有了好的解决方案
      GLint m_viewport[4];
      glGetIntegerv(GL_VIEWPORT, m_viewport);
      int YposTMP = m_viewport[3] - Ypos - 1;