我正在尝试实现一个着色器,计算光线在物体的前表面和后表面间的折射。为此,我需要使用正常深度测试(GL_LESS)来渲染折射几何体的前表面,并使用反向深度测试(GL_GREATER)来渲染其后表面。这将允许我计算从后表面到前表面的距离。
不幸的是,我只能一次渲染其中一个,而且我无法弄清楚如何将两个深度信息作为纹理传递到着色器中。
着色器本身不应该成为问题,但我难以设置OpenGL以便它提供传递给着色器所需的所有内容!
为了完全清晰,我需要将两个纹理传递给我的着色器: - 一个纹理包含物体前表面的深度信息 - 一个纹理包含物体后表面的深度信息
以下大致是我的操作(简化代码以避免太乱)。
如果将其渲染到FBO上,然后在四边形上渲染,它就能完美地工作。在上面的示例中,我将其渲染了200次到FBO上,然后停止了对FBO的渲染,并在我的全屏四边形上显示纹理。
以下是预期结果(为了显示目的,我将第二个几何体渲染得比第一个小):
代码如下(与可工作图像的代码几乎相同,但每帧都要渲染四边形)。
但是,现在我的问题出现在渲染到FBO时,然后尝试在每一帧显示四边形时。我得到了一个奇怪的结果,似乎只考虑了几何的一小部分:
我无法弄清楚为什么会发生这种情况。它明确地渲染到深度纹理,但似乎由于某种原因,渲染全屏幕四边形会改变FBO几何的渲染。
[编辑] 我刚刚尝试保存OpenGL状态,并在四边形之后恢复它...
不幸的是,我只能一次渲染其中一个,而且我无法弄清楚如何将两个深度信息作为纹理传递到着色器中。
着色器本身不应该成为问题,但我难以设置OpenGL以便它提供传递给着色器所需的所有内容!
为了完全清晰,我需要将两个纹理传递给我的着色器: - 一个纹理包含物体前表面的深度信息 - 一个纹理包含物体后表面的深度信息
以下大致是我的操作(简化代码以避免太乱)。
void FBO::init() {
initDepthTexture();
initFBO();
}
void FBO::initDepthTexture() {
//32 bit depth texture, mWidth*mHeight
glGenTextures(1, &mDepthTex);
glBindTexture(GL_TEXTURE_2D, mDepthTex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE,
GL_COMPARE_R_TO_TEXTURE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
//NULL means reserve texture memory, but texels are undefined
//You can also try GL_DEPTH_COMPONENT16, GL_DEPTH_COMPONENT24 for the internal format.
//If GL_DEPTH24_STENCIL8_EXT, go ahead and use it (GL_EXT_packed_depth_stencil)
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, mWidth, mHeight, 0,
GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
}
void FBO::initFBO() {
glGenFramebuffersEXT(1, &mFrameBuffer);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFrameBuffer);
//Attach
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,
GL_TEXTURE_2D, mDepthTex, 0);
//-------------------------
//Does the GPU support current FBO configuration?
//Before checking the configuration, you should call these 2 according to the spec.
//At the very least, you need to call glDrawBuffer(GL_NONE)
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
checkFBO();
renderToScreen();
}
void FBO::renderToFBO() {
cout << "Render to FBO: " << mFrameBuffer << endl;
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, mFrameBuffer); // Bind our frame buffer for rendering
//-------------------------
//----and to render to it, don't forget to call
//At the very least, you need to call glDrawBuffer(GL_NONE)
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
}
/**
* Static
*/
void FBO::renderToScreen() {
cout << "Render to screen " << endl;
// Finish all operations
//glFlush();
//-------------------------
//If you want to render to the back buffer again, you must bind 0 AND THEN CALL glDrawBuffer(GL_BACK)
//else GL_INVALID_OPERATION will be raised
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // Unbind our texture
glDrawBuffer(GL_BACK);
glReadBuffer(GL_BACK);
}
以下是我如何使用FBOs: 在渲染函数之外,我首先创建两个FBO,请查看init()函数以了解其初始化方式。 在第一个FBO上,我从前面渲染几何深度 在第二个FBO上,我从后面渲染几何深度 然后将两个深度纹理渲染到全屏四边形中。
void Viewer::onRender() {
FBO::renderToScreen();
// XXX: Need of Z-Depth sorting to get alpha blending right!!
glEnable(GL_DEPTH_TEST);
glClearColor(0., 0., 0.2, 1.);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glClearDepth(1.);
glDepthFunc(GL_LESS);
// set the projection transformation
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLdouble) m_width / (GLdouble) m_height,
m_scale * 5.0, m_scale * 10000.0);
// set the model transformation
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glm::vec3 pos = mCamera->getPosition();
glm::vec3 view = mCamera->getView();
glm::vec3 up = mCamera->getUp();
gluLookAt(pos.x, pos.y, pos.z, view.x, view.y, view.z, up.x, up.y,
up.z);
static float rotationAngle = 0;
rotationAngle+=5;
static int i = 0;
if(i++ < 200) {
/**
* Render geometry twice to FBOs
*/
mFBO->renderToFBO();
glClear(GL_DEPTH_BUFFER_BIT);
glClearDepth(0.);
glDepthFunc(GL_LESS);
glPushMatrix();
glRotatef(1, 1, 0, 120);
glColor3f(0., 1., 0.);
// Draw teapot
glutSolidTeapot(1.8);
glPopMatrix();
mFBO2->renderToFBO();
glClear(GL_DEPTH_BUFFER_BIT);
glClearDepth(0.);
glDepthFunc(GL_GREATER);
glPushMatrix();
glColor3f(0., 1., 0.);
// Draw teapot
glutSolidTeapot(3.5);
glPopMatrix();
/**
* Render the same geometry to the screen
*/
FBO::renderToScreen();
} else {
mShader->enable();
mShader->setTextureFromId("frontDepth", mFBO->getDepthTextureId());
mShader->setTextureFromId("backDepth", mFBO2->getDepthTextureId());
glBegin(GL_QUADS); // Draw A Quad
glTexCoord2f(0, 1);
glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
glTexCoord2f(1, 1);
glVertex3f(1.0f, 1.0f, 0.0f); // Top Right
glTexCoord2f(1, 0);
glVertex3f(1.0f, -1.0f, 0.0f); // Bottom Right
glTexCoord2f(0, 0);
glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
glEnd(); // Done Drawing The Quad
mShader->disable();
}
}
如果将其渲染到FBO上,然后在四边形上渲染,它就能完美地工作。在上面的示例中,我将其渲染了200次到FBO上,然后停止了对FBO的渲染,并在我的全屏四边形上显示纹理。
以下是预期结果(为了显示目的,我将第二个几何体渲染得比第一个小):
代码如下(与可工作图像的代码几乎相同,但每帧都要渲染四边形)。
void Viewer::onRender() {
FBO::renderToScreen();
// XXX: Need of Z-Depth sorting to get alpha blending right!!
glEnable(GL_DEPTH_TEST);
glClearColor(0., 0., 0.2, 1.);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glClearDepth(1.);
glDepthFunc(GL_LESS);
// set the projection transformation
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, (GLdouble) m_width / (GLdouble) m_height,
m_scale * 5.0, m_scale * 10000.0);
// set the model transformation
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glm::vec3 pos = mCamera->getPosition();
glm::vec3 view = mCamera->getView();
glm::vec3 up = mCamera->getUp();
gluLookAt(pos.x, pos.y, pos.z, view.x, view.y, view.z, up.x, up.y,
up.z);
static float rotationAngle = 0;
rotationAngle+=5;
/**
* Render geometry twice to FBOs
*/
mFBO->renderToFBO();
glClear(GL_DEPTH_BUFFER_BIT);
glClearDepth(0.);
glDepthFunc(GL_LESS);
glPushMatrix();
glRotatef(1, 1, 0, 120);
glColor3f(0., 1., 0.);
// Draw teapot
glutSolidTeapot(1.8);
glPopMatrix();
mFBO2->renderToFBO();
glClear(GL_DEPTH_BUFFER_BIT);
glClearDepth(0.);
glDepthFunc(GL_GREATER);
glPushMatrix();
glColor3f(0., 1., 0.);
// Draw teapot
glutSolidTeapot(3.5);
glPopMatrix();
/**
* Render both depth texture on a fullscreen quad
**/
FBO::renderToScreen();
mShader->enable();
mShader->setTextureFromId("frontDepth", mFBO->getDepthTextureId());
mShader->setTextureFromId("backDepth", mFBO2->getDepthTextureId());
glBegin(GL_QUADS); // Draw A Quad
glTexCoord2f(0, 1);
glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
glTexCoord2f(1, 1);
glVertex3f(1.0f, 1.0f, 0.0f); // Top Right
glTexCoord2f(1, 0);
glVertex3f(1.0f, -1.0f, 0.0f); // Bottom Right
glTexCoord2f(0, 0);
glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
glEnd(); // Done Drawing The Quad
mShader->disable();
}
}
但是,现在我的问题出现在渲染到FBO时,然后尝试在每一帧显示四边形时。我得到了一个奇怪的结果,似乎只考虑了几何的一小部分:
![Only a small wrong part of the geometry](https://istack.dev59.com/smpaE.webp)
[编辑] 我刚刚尝试保存OpenGL状态,并在四边形之后恢复它...
FBO::renderToScreen();
glPushAttrib(GL_ALL_ATTRIB_BITS);
mShader->enable();
mShader->setTextureFromId("frontDepth", mFBO->getDepthTextureId());
mShader->setTextureFromId("backDepth", mFBO2->getDepthTextureId());
glBegin(GL_QUADS); // Draw A Quad
glTexCoord2f(0, 1);
glVertex3f(-1.0f, 1.0f, 0.0f); // Top Left
glTexCoord2f(1, 1);
glVertex3f(1.0f, 1.0f, 0.0f); // Top Right
glTexCoord2f(1, 0);
glVertex3f(1.0f, -1.0f, 0.0f); // Bottom Right
glTexCoord2f(0, 0);
glVertex3f(-1.0f, -1.0f, 0.0f); // Bottom Left
glEnd(); // Done Drawing The Quad
mShader->disable();
glPopAttrib();
好的,这样做可以让我自由地在场景中移动、添加物体而不会遇到任何问题。然而,我仍然很好奇是哪个状态改变导致了渲染过程的失败,你有什么想法吗?