我正在尝试实现一个着色器,通过两个表面计算光线折射:物体的背面和正面。 为此,我需要使用正常深度测试(GL_LESS)和反向深度测试(GL_GREATER)渲染折射几何体。它可以让我计算从背面到正面的距离。 不幸的是,我只设法一次渲染其中一个,我无法弄清楚如何将两个深度信息作为纹理传递给着色器。
着色器本身应该不是问题,但我正在努力设置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);
}
以下是我如何使用FBO: 我首先在render函数之外创建两个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然后在四边形上渲染,这是完美的。在上面的示例中,我向FBO渲染200次,然后停止渲染到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时,我的问题出现了,然后尝试在每一帧显示四边形。 我得到了一个奇怪的结果,似乎只考虑了几何的一小部分:
我无法弄清楚为什么会这样。它肯定会渲染到深度纹理,但似乎由于某种原因渲染全屏四边形会改变FBO几何体的渲染。
[编辑]我刚尝试保存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();
嗯,这很有效,我可以在场景中移动添加对象并且没有任何麻烦。 但是我仍然很好奇哪个州的变化可能会导致渲染过程失败这么多,任何想法?
答案 0 :(得分:1)
你要做的是一种名为&#34; Depth Peeling&#34;这基本上可以被描述为插入的形式分类到多个深度缓冲层中。网上有很多演讲和论文。
答案 1 :(得分:1)
由于问题已得到解决(即使我不明白哪个状态正在关闭),这里是我的FBO类和渲染函数的完整代码,以防有人遇到同样的问题:
/*
* FBO.cpp
*
* Created on: 28 Mar 2013
* Author: arnaud
*/
// Include GLEW
#include <GL/glew.h>
#include "FBO.h"
#include <GL/glext.h>
#include <iostream>
#include "FBOException.h"
using namespace std;
FBO::FBO(int width, int height) {
mWidth = width;
mHeight = height;
// TODO Auto-generated constructor stubc
init();
}
FBO::~FBO() {
// TODO Auto-generated destructor stub
glDeleteFramebuffersEXT(1, &mFrameBuffer);
}
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::checkFBO() throw () {
GLenum status;
status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
switch (status) {
case GL_FRAMEBUFFER_COMPLETE_EXT:
cout << "Good Framebuffer" << endl;
break;
case GL_FRAMEBUFFER_UNDEFINED:
throw new FBOException(
"Framebuffer undefined. Usually returned if returned if target is the default framebuffer, but the default framebuffer does not exist.");
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
throw new FBOException(
"Incomplete Attachement: is returned if any of the framebuffer attachment points are framebuffer incomplete.");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
throw new FBOException(
"Incomplete Missing Attachment: is returned if the framebuffer does not have at least one image attached to it.");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
throw new FBOException(
"Incomplete Draw Buffer: is returned if the value of GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for any color attachment point(s) named by GL_DRAWBUFFERi");
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
throw new FBOException(
"Incomplete Read Buffer: is returned if GL_READ_BUFFER is not GL_NONE and the value of\\"
" GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE is GL_NONE for the color attachment point named by GL_READ_BUFFER");
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
throw new FBOException(
"Framebuffer Unsupported: is returned if the combination of internal formats of the attached images violates an implementation-dependent set of restrictions.");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
throw new FBOException("Incomplete Multisample");
break;
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
throw new FBOException("Incomplete Layer Targets");
break;
default:
throw new FBOException("Bad Framebuffer");
}
}
/****
* PUBLIC Functions
*/
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);
}
这是渲染功能
void Viewer::onRender() {
// Get elapsed time since last loop
sf::Time time = mClock.getElapsedTime();
float ellapsedTime = time.asMilliseconds();
if (time.asMilliseconds() > 1000 / 60) {
// 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();
glColor3f(0., 1., 0.);
// Draw teapot
glutSolidTeapot(3.5);
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();
// XXX: Save attribs bits to fix FBO problem... (why is this needed!?)
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();
}
}