我有各种姿势的相同复杂物体的几个网格(~100),旋转和平移参数略有不同。该物体由多个刚性部件组成,如手臂和腿部。
目标是生成一个独特的灰度图片,显示这些姿势对特定身体部位的累积。获得的热图给出了身体部位可能的像素位置的概念,其中白色代表最大概率,黑色最小(较高概率)。说我对腿的积累很感兴趣。如果许多腿部姿势样本位于相同的(x,y)像素位置,那么我希望在那里看到亮像素。最终腿部姿势可能不完全重叠,所以我也期望看到平滑过渡到腿部轮廓边界周围的黑色低概率。
为了解决这个问题,我决定在OpenGL帧缓冲区中使用渲染,因为已知它们在计算上很便宜,并且因为我需要经常运行这个累积过程。
我做的是以下内容。我使用GL_BLEND在相同的帧缓冲区'fboLegsId'上累积了我感兴趣的身体部位的相应渲染(让我们仍保持腿部示例)。为了区分腿 和身体的其他部分,我用两种颜色纹理网格:
腿的rgba(灰色,灰色,灰色,255),灰色= 255 /样本数= 255/100
rgba(0,0,0,0)用于身体其他部分
然后我通过执行以下操作累积100个渲染(腿部应该总结为白色= 255):
glBindFramebuffer(GL_FRAMEBUFFER, fboLegsId);
glClearColor(0,0,0,255);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
for each sample s = 0...100
mesh.render(pose s);
end
glReadPixels(...)
这几乎和我预期的一样。我确实获得了我想要的平滑灰度热图。然而,存在自我遮挡问题 即使我只使用1个样本也会出现。比如说一个姿势样本,其中一个手臂在腿前移动,部分遮挡它们。我期望在渲染过程中取消被遮挡的腿部的影响。然而,它呈现为好像手臂是不可见/半透明的,允许完全显示后面的像素。这会导致错误的渲染,从而导致错误的累积。
如果我简单地禁用混合,我会看到正确的自遮挡感知结果。所以,显然问题在于混合时间。
我还尝试了不同的混合功能,到目前为止,下面的一个产生了更接近自我遮挡意识积累方法的结果: glBlendFunc(GL_ONE,GL_SRC_ALPHA); 无论如何,这里仍然存在一个问题:一个样本看起来现在正确;两个或多个累积样本代替显示与其他样本重叠的假象。如果像素不腿的一部分,则看起来每个累积替换当前缓冲像素。并且如果在手臂前面发现了多次腿,那么它会变得越来越暗,而不是更轻更亮。 我尝试通过在每次渲染迭代中清除深度缓冲来实现深度计算来解决这个问题,但这并没有解决问题。
我觉得在我的方法中存在任何概念上的错误,或某处的小错误。
我根据预期执行的建议尝试了不同的方法。现在我正在使用2帧缓冲区。第一个(SingleFBO)用于渲染具有正确自遮挡处理的单个样本。第二个(AccFBO)用于使用混合从第一个缓冲区累积2D纹理。请检查下面的代码:
// clear the accumulation buffer
glBindFramebuffer(GL_FRAMEBUFFER, AccFBO);
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for each sample s = 0...100
{
// set rendering destination to SingleFBO
glBindFramebuffer(GL_FRAMEBUFFER, SingleFBO);
glClearColor(0.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
mesh->render(pose s);
glDisable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
// set rendering destination to the accumulation buffer
glBindFramebuffer(GL_FRAMEBUFFER, AccFBO);
glClear(GL_DEPTH_BUFFER_BIT);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);
// draw texture from previous buffer to a quad
glBindTexture(GL_TEXTURE_2D, textureLeg);
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDepthMask(GL_FALSE);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glBegin( GL_QUADS );
{
glTexCoord2f(0,0); glVertex2f(-1.0f, -1.0f);
glTexCoord2f(1,0); glVertex2f(1.0f, -1.0f);
glTexCoord2f(1,1); glVertex2f(1.0f, 1.0f);
glTexCoord2f(0,1); glVertex2f(-1.0f, 1.0f);
}
glEnd();
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
// restore
glDisable(GL_TEXTURE_2D);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glDepthMask(GL_TRUE);
glDisable(GL_BLEND);
}
glBindFramebuffer(GL_FRAMEBUFFER, AccFBO);
glReadPixels(...)
请检查我的(标准)代码以初始化SingleFBO(类似于AccFBO):
// create a texture object
glGenTextures(1, &textureLeg);
glBindTexture(GL_TEXTURE_2D, textureLeg);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0,
GL_RGB, GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);
// create a renderbuffer object to store depth info
glGenRenderbuffers(1, &rboLeg);
glBindRenderbuffer(GL_RENDERBUFFER, rboLeg);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT,
width, height);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
// create a framebuffer object
glGenFramebuffers(1, &SingleFBO);
glBindFramebuffer(GL_FRAMEBUFFER, SingleFBO);
// attach the texture to FBO color attachment point
glFramebufferTexture2D(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER
GL_COLOR_ATTACHMENT0, // 2. attachment point
GL_TEXTURE_2D, // 3. tex target: GL_TEXTURE_2D
textureLeg, // 4. tex ID
0); // 5. mipmap level: 0(base)
// attach the renderbuffer to depth attachment point
glFramebufferRenderbuffer(GL_FRAMEBUFFER, // 1. fbo target: GL_FRAMEBUFFER
GL_DEPTH_ATTACHMENT, // 2. attachment point
GL_RENDERBUFFER, // 3. rbo target: GL_RENDERBUFFER
rboLeg); // 4. rbo ID
// check FBO status
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
error(...);
// switch back to window-system-provided framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
答案 0 :(得分:0)
这是一种不同的方法:
创建两个帧缓冲区:normal
和acc
。 normal
帧缓冲区应该有纹理存储(使用glFramebufferTexture2D
)。
这是基本算法:
acc
清除为黑色normal
,清除为黑色,渲染场景为白色腿,其他部分为黑色acc
,渲染全屏矩形,上面有normal
纹理,混合模式为GL_ONE,GL_ONE acc
因此,基本上,acc
将包含各个帧的总和。