Commit 3625e353 authored by Christopher Tenter's avatar Christopher Tenter

removed depth peeling functions

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@15830 383ad7c9-94d9-4d36-a494-682f7c89f535
parent 20c0fed3
......@@ -13,64 +13,11 @@
using namespace ACG;
// =================================================
// depth peeling shader modifier
class PeelLayerModifier : public ShaderModifier
{
public:
void modifyFragmentIO(ShaderGenerator* _shader)
{
_shader->addUniform("sampler2D g_DepthLayer");
}
void modifyFragmentBeginCode(QStringList* _code)
{
// compare current depth with previous layer
_code->push_back("float dp_prevDepth = texture(g_DepthLayer, sg_vScreenPos).x;");
_code->push_back("if (gl_FragCoord.z <= dp_prevDepth) discard;");
}
void modifyFragmentEndCode(QStringList* _code)
{
_code->push_back("outFragment = vec4(sg_cColor.rgb * sg_cColor.a, sg_cColor.a);");
}
static PeelLayerModifier instance;
};
class PeelInitModifier : public ShaderModifier
{
public:
void modifyFragmentEndCode(QStringList* _code)
{
_code->push_back("outFragment = vec4(sg_cColor.rgb * sg_cColor.a, 1.0 - sg_cColor.a);");
}
static PeelInitModifier instance;
};
PeelInitModifier PeelInitModifier::instance;
PeelLayerModifier PeelLayerModifier::instance;
// =================================================
// internal flags
#define RENDERFLAG_ALLOW_PEELING 1
// =================================================
Renderer::Renderer()
: numLights_(0), renderObjects_(0),
screenQuadVBO_(0), screenQuadDecl_(0), depthPeelingSupport_(1),
peelBlend_(0), peelFinal_(0), peelDepthCopy_(0), peelQueryID_(0)
: numLights_(0), renderObjects_(0)
{
for (int i = 0; i < SG_MAX_SHADER_LIGHTS; ++i)
lightTypes_[i] = SG_LIGHT_POINT;
......@@ -108,15 +55,6 @@ void Renderer::addRenderObject(RenderObject* _renderObject)
p->internalFlags_ = 0;
// allow potential depth peeling only for compatible
// render states
if (p->alpha < 1.0f &&
p->depthTest &&
p->depthWrite && (p->depthFunc == GL_LESS ||
p->depthFunc == GL_LEQUAL))
p->internalFlags_ = RENDERFLAG_ALLOW_PEELING;
// precompile shader
ShaderCache::getInstance()->getProgram(&p->shaderDesc);
......@@ -239,6 +177,8 @@ void Renderer::render(ACG::GLState* _glState, Viewer::ViewerProperties& _propert
qsort(sortedObjects, numRenderObjects, sizeof(RenderObject*), cmpPriority);
// dumpRenderObjectsToText("../../dump_ro.txt", sortedObjects);
// render
......@@ -261,215 +201,8 @@ void Renderer::render(ACG::GLState* _glState, Viewer::ViewerProperties& _propert
glClearColor(clearColor[0], clearColor[1], clearColor[2], 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (depthPeelingSupport_)
{
// find last transparent object to peel
int lastPeeledObject = -1;
for (int i = numRenderObjects - 1; i > lastPeeledObject; --i)
{
if ((sortedObjects[i]->internalFlags_ & RENDERFLAG_ALLOW_PEELING) && sortedObjects[i]->alpha < 0.99f)
lastPeeledObject = i;
}
if (lastPeeledObject == -1)
{
// no transparent objects
for (size_t i = 0; i < numRenderObjects; ++i)
renderObject(sortedObjects[i]);
}
else
{
// depth peeling for transparency
updateViewerResources(_properties.viewerId(), _glState->viewport_width(), _glState->viewport_height());
ViewerResources* viewRes = &viewerRes_[_properties.viewerId()];
// begin peeling
// draw first layer
// target depth buffer: viewRes->peelTarget_[0]
glBindFramebuffer(GL_FRAMEBUFFER, viewRes->peelBlendFbo_);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glDepthMask(1);
glColorMask(1,1,1,1);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw opaque objects first
for (int i = 0; i <= lastPeeledObject; ++i)
{
if (!(sortedObjects[i]->internalFlags_ & RENDERFLAG_ALLOW_PEELING) || sortedObjects[i]->alpha >= 0.99f)
renderObject(sortedObjects[i]);
}
glDepthMask(1);
glColorMask(1,1,1,1);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDisable(GL_BLEND);
glDisable(GL_ALPHA_TEST);
for (size_t i = 0; i < numRenderObjects; ++i)
{
if ((sortedObjects[i]->internalFlags_ & RENDERFLAG_ALLOW_PEELING) && sortedObjects[i]->alpha < 0.99f)
{
GLSL::Program* initProg = ShaderCache::getInstance()->getProgram(&sortedObjects[i]->shaderDesc, PeelInitModifier::instance);
renderObject(sortedObjects[i], initProg, true);
}
}
// TODO:
// copy front layer depth buffer to window depth buffer
// or even better: peel from back to front
// peel layers, we start at index 1 instead of 0
// since the front layer is already initialized in
// depth buffer 0 and we want to extract the second one now
for (int i = 1; i < 10; ++i)
{
// pointer to current and previous layer
PeelLayer* curr = viewRes->peelTargets_ + (i & 1);
PeelLayer* prev = viewRes->peelTargets_ + 1 - (i & 1);
// 1st peel next layer
glBindFramebuffer(GL_FRAMEBUFFER, curr->fbo);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_BLEND);
glEnable(GL_DEPTH_TEST);
// count # passed fragments
glBeginQuery(GL_SAMPLES_PASSED, peelQueryID_);
// bind previous depth layer to texture unit 4
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_2D, prev->depthTex);
// render scene
for (size_t k = 0; k < numRenderObjects; ++k)
{
if ((sortedObjects[k]->internalFlags_ & RENDERFLAG_ALLOW_PEELING) && sortedObjects[k]->alpha < 0.99f)
{
GLSL::Program* peelProg = ShaderCache::getInstance()->getProgram(&sortedObjects[k]->shaderDesc, PeelLayerModifier::instance);
peelProg->use();
peelProg->setUniform("g_DepthLayer", 4);
renderObject(sortedObjects[k], peelProg, true);
}
}
glEndQuery(GL_SAMPLES_PASSED);
// 2nd underblend layer with current scene
// (fullscreen pass)
glBindFramebuffer(GL_FRAMEBUFFER, viewRes->peelBlendFbo_);
glDepthMask(1);
glColorMask(1,1,1,1);
glDisable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendEquation(GL_FUNC_ADD);
glBlendFuncSeparate(GL_DST_ALPHA, GL_ONE,
GL_ZERO, GL_ONE_MINUS_SRC_ALPHA);
peelBlend_->use();
peelBlend_->setUniform("BlendTex", 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, curr->colorTex);
drawProjQuad(peelBlend_);
glDisable(GL_BLEND);
GLuint passedSamples;
glGetQueryObjectuiv(peelQueryID_, GL_QUERY_RESULT, &passedSamples);
if (passedSamples == 0)
break;
}
// copy to back buffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDrawBuffer(GL_BACK);
glDepthMask(1);
glColorMask(1,1,1,1);
glDisable(GL_DEPTH_TEST);
peelFinal_->use();
ACG::Vec3f bkgColor;
bkgColor[0] = _properties.backgroundColor()[0];
bkgColor[1] = _properties.backgroundColor()[1];
bkgColor[2] = _properties.backgroundColor()[2];
peelFinal_->setUniform("BkgColor", bkgColor);
peelFinal_->setUniform("SceneTex", 0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, viewRes->peelBlendTex_);
drawProjQuad(peelFinal_);
ACG::glCheckErrors();
// draw rest of scene
glEnable(GL_DEPTH_TEST);
/*
// draw rest of opaque objects
for (size_t i = lastPeeledObject + 1; i < numRenderObjects; ++i)
renderObject(sortedObjects[i]);
*/
}
}
else
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (size_t i = 0; i < numRenderObjects; ++i)
renderObject(sortedObjects[i]);
}
// restore commmon opengl state
......@@ -613,6 +346,7 @@ void Renderer::bindObjectRenderStates(ACG::RenderObject* _obj)
else
glDisable(GL_DEPTH_TEST);
glDepthMask(_obj->depthWrite ? GL_TRUE : GL_FALSE);
glColorMask(_obj->colorWriteMask[0], _obj->colorWriteMask[1], _obj->colorWriteMask[2], _obj->colorWriteMask[3]);
......@@ -678,6 +412,8 @@ void Renderer::renderObject(ACG::RenderObject* _obj,
drawObject(_obj);
ACG::glCheckErrors();
// deactivate vertex declaration to avoid errors
_obj->vertexDecl->deactivateShaderPipeline(prog);
......@@ -761,245 +497,12 @@ void Renderer::collectLightNodes( ACG::SceneGraph::BaseNode* _node )
int Renderer::getNumRenderObjects() const
{
// int i = 0;
// for (InternalRenderObject* r = renderObjects_; r; ++i, r = r->next);
// return i;
return renderObjects_.size();
}
Renderer::ViewerResources::ViewerResources()
: glWidth_(0), glHeight_(0), peelBlendTex_(0), peelBlendFbo_(0)
{
memset(peelTargets_, 0, sizeof(peelTargets_));
}
void Renderer::updateViewerResources(int _viewerId,
unsigned int _newWidth,
unsigned int _newHeight)
{
initDepthPeeling();
// allocate opengl resources
// screenquad
if (!screenQuadDecl_)
{
screenQuadDecl_ = new VertexDeclaration();
screenQuadDecl_->addElement(GL_FLOAT, 3, VERTEX_USAGE_POSITION, 0, 0);
}
if (!screenQuadVBO_)
{
float quad[] =
{
-1.0f, -1.0f, -1.0f,
1.0f, -1.0f, -1.0f,
1.0f, 1.0f, -1.0f,
-1.0f, 1.0f, -1.0f
};
glGenBuffers(1, &screenQuadVBO_);
glBindBuffer(GL_ARRAY_BUFFER, screenQuadVBO_);
glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
ACG::glCheckErrors();
}
if (!_newWidth || !_newHeight) return;
ViewerResources* view = &viewerRes_[_viewerId];
if (view->glHeight_ == _newHeight &&
view->glWidth_ == _newWidth)
return;
view->glWidth_ = _newWidth;
view->glHeight_ = _newHeight;
// update depth peeling textures
if (depthPeelingSupport_)
{
for (int i = 0; i < 2; ++i)
{
PeelLayer* dst = view->peelTargets_ + i;
if (!dst->colorTex)
glGenTextures(1, &dst->colorTex);
if (!dst->depthTex)
glGenTextures(1, &dst->depthTex);
if (!dst->colorTex || !dst->depthTex) // out of memory
continue;
glBindTexture(GL_TEXTURE_2D, dst->colorTex);
// clamp, point filter
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _newWidth, _newHeight, 0, GL_RGBA, GL_FLOAT, 0);
glBindTexture(GL_TEXTURE_2D, dst->depthTex);
// clamp, point filter
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, _newWidth, _newHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
ACG::glCheckErrors();
// fbo
if (!dst->fbo)
{
glGenFramebuffers(1, &dst->fbo);
glBindFramebuffer(GL_FRAMEBUFFER, dst->fbo);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, dst->colorTex, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, dst->depthTex, 0);
GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(fboStatus != GL_FRAMEBUFFER_COMPLETE)
printf("ViewWorld: fbo failed to initialize : %d\n", fboStatus);
}
}
if (!view->peelBlendTex_)
glGenTextures(1, &view->peelBlendTex_);
if (view->peelBlendTex_)
{
glBindTexture(GL_TEXTURE_2D, view->peelBlendTex_);
// clamp, point filter
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, _newWidth, _newHeight, 0, GL_RGBA, GL_FLOAT, 0);
}
if (!view->peelBlendFbo_)
{
glGenFramebuffers(1, &view->peelBlendFbo_);
glBindFramebuffer(GL_FRAMEBUFFER, view->peelBlendFbo_);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, view->peelBlendTex_, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, view->peelTargets_[0].depthTex, 0);
GLenum fboStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(fboStatus != GL_FRAMEBUFFER_COMPLETE)
printf("ViewWorld: fbo failed to initialize : %d\n", fboStatus);
}
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
ACG::glCheckErrors();
}
void Renderer::initDepthPeeling()
{
// register shader modifiers
ShaderProgGenerator::registerModifier(&PeelInitModifier::instance);
ShaderProgGenerator::registerModifier(&PeelLayerModifier::instance);
const char* ShaderFiles[] =
{
"DepthPeeling/screenquad.glsl",
"DepthPeeling/blend.glsl",
"DepthPeeling/final.glsl",
};
GLSL::Shader* tempShaders[3] = {0};
for (int i = 0; i < 3; ++i)
{
QString shaderFile = OpenFlipper::Options::shaderDirStr() + QDir::separator() + QString(ShaderFiles[i]);
if (i == 0) // screenquad is a vertex shader
tempShaders[i] = GLSL::loadVertexShader(shaderFile.toUtf8());
else // "blend", "final" are fragment shaders
tempShaders[i] = GLSL::loadFragmentShader(shaderFile.toUtf8());
if (!tempShaders[i]) {
log(LOGERR, QString(ShaderFiles[i]) + QString(" could not be loaded and compiled"));
return;
}
}
// create programs
if (!peelBlend_)
{
peelBlend_ = new GLSL::Program();
peelBlend_->attach(tempShaders[0]);
peelBlend_->attach(tempShaders[1]);
peelBlend_->link();
}
if (!peelFinal_)
{
peelFinal_ = new GLSL::Program();
peelFinal_->attach(tempShaders[0]);
peelFinal_->attach(tempShaders[2]);
peelFinal_->link();
}
for (int i = 0; i < 3; ++i)
delete tempShaders[i];
// occ query id
if (!peelQueryID_)
glGenQueries(1, &peelQueryID_);
ACG::glCheckErrors();
}
void Renderer::drawProjQuad(GLSL::Program* _prog)
{
glBindBuffer(GL_ARRAY_BUFFER, screenQuadVBO_);
screenQuadDecl_->activateShaderPipeline(_prog);
glPolygonMode(GL_FRONT, GL_FILL);
glDrawArrays(GL_QUADS, 0, 4);
screenQuadDecl_->deactivateShaderPipeline(_prog);
}
QString Renderer::checkOpenGL()
{
......
......@@ -115,7 +115,7 @@ public:
A renderobject is a collection of opengl states, buffers and parameters,
that correspond to exactly one draw call.
*/
void addRenderObject(ACG::RenderObject* _renderObject);
virtual void addRenderObject(ACG::RenderObject* _renderObject);
protected:
......@@ -201,84 +201,5 @@ protected:
std::vector<ACG::RenderObject> renderObjects_;
// draw a projected quad in [-1, -1] - [1, 1] range
void drawProjQuad(GLSL::Program* _prog);
/// vbo containing a quad in projection space
GLuint screenQuadVBO_;
ACG::VertexDeclaration* screenQuadDecl_;
// single layer depth peeling
struct PeelLayer
{
/// target framebuffer for colorTex and depthTex
GLuint fbo;
/// color rendertarget
GLuint colorTex;
/// depth-buf rendertarget
GLuint depthTex;
};
/// is depth peeling supported
bool depthPeelingSupport_;
/// blends one depth-layer into the current scene target
GLSL::Program* peelBlend_;
/// final copy into back-buffer
GLSL::Program* peelFinal_;
/**
Copy depth-texture of first layer into hardware z-buffer.
This is needed for post-processing or renderobjects with low priority.
*/
GLSL::Program* peelDepthCopy_;
/// occlusion query determining end of peeling (last layer)
GLuint peelQueryID_;
/// Collection of framebuffers for each viewport
struct ViewerResources
{
ViewerResources();
/// viewer window width
unsigned int glWidth_;
/// viewer window height
unsigned int glHeight_;
// depth peeling textures
/// ping pong between two consecutive layers
PeelLayer peelTargets_[2];
GLuint peelBlendTex_;
GLuint peelBlendFbo_;
};
/// Allocate framebuffers and load shaders for depth-peeling.
void initDepthPeeling();
/// Change viewport size for allocated rendertargets.
void updateViewerResources(int _viewerId, unsigned int _newWidth, unsigned int _newHeight);
/**
Stores framebuffer resources for each viewport.
Mapping: viewerID -> ViewerResources
*/
std::map<int, ViewerResources> viewerRes_;
};