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
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <stdlib.h>
#include <ACG/GL/gl.hh>
#include <ACG/ShaderUtils/GLSLShader.hh>
#include "Renderer.hh"
#include <ACG/GL/ShaderCache.hh>
#include <ACG/GL/VertexDeclaration.hh>
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)
{
for (int i = 0; i < SG_MAX_SHADER_LIGHTS; ++i)
lightTypes_[i] = SG_LIGHT_POINT;
}
Renderer::~Renderer()
{
}
void Renderer::initializePlugin()
{
ACG::ShaderProgGenerator::setShaderDir(OpenFlipper::Options::shaderDirStr());
}
void Renderer::addRenderObject(RenderObject* _renderObject)
{
// do some more checks for error detection
if (!_renderObject->vertexDecl)
std::cout << "error: missing vertex declaration" << std::endl;
else
{
renderObjects_.push_back(*_renderObject);
RenderObject* p = &renderObjects_.back();
if (!p->shaderDesc.numLights)
p->shaderDesc.numLights = numLights_;
else if (p->shaderDesc.numLights < 0 || p->shaderDesc.numLights >= SG_MAX_SHADER_LIGHTS)
p->shaderDesc.numLights = 0;
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);
}
}
void Renderer::collectRenderObjects( GLState* _glState, SceneGraph::DrawModes::DrawMode _drawMode, SceneGraph::BaseNode* _sceneGraphRoot )
{
// collect light sources
collectLightNodes(_sceneGraphRoot);
// flush render objects
// clear() may actually free memory, resulting in capacity = 0
renderObjects_.resize(0);
// default material needed
ACG::SceneGraph::Material defMat;
defMat.baseColor(Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
defMat.ambientColor(Vec4f(0.2f, 0.2f, 0.2f, 1.0f));
defMat.diffuseColor(Vec4f(0.6f, 0.6f, 0.6f, 1.0f));
defMat.specularColor(Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
defMat.shininess(1.0f);
// defMat.alphaValue(1.0f);
// collect renderables
traverseRenderableNodes(_glState, _drawMode, _sceneGraphRoot, &defMat);
}
void Renderer::traverseRenderableNodes( GLState* _glState, SceneGraph::DrawModes::DrawMode _drawMode, SceneGraph::BaseNode* _node, const SceneGraph::Material* _mat )
{
if (_node)
{
SceneGraph::BaseNode::StatusMode status(_node->status());
bool process_children(status != SceneGraph::BaseNode::HideChildren);
SceneGraph::DrawModes::DrawMode nodeDM = _node->drawMode();
if (nodeDM == SceneGraph::DrawModes::DEFAULT)
nodeDM = _drawMode;
// If the subtree is hidden, ignore this node and its children while rendering
if (status != SceneGraph::BaseNode::HideSubtree)
{
if ( _node->status() != SceneGraph::BaseNode::HideNode )
_node->enter(*_glState, _drawMode);
if (_node->status() != SceneGraph::BaseNode::HideNode)
_node->getRenderObjects(this, *_glState, nodeDM, _mat);
// fetch material
SceneGraph::MaterialNode* matNode = dynamic_cast<SceneGraph::MaterialNode*>(_node);
if (matNode)
_mat = &matNode->material();
if (process_children)
{
SceneGraph::BaseNode::ChildIter cIt, cEnd(_node->childrenEnd());
// Process all children which are not second pass
for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
if (~(*cIt)->traverseMode() & SceneGraph::BaseNode::SecondPass)
traverseRenderableNodes( _glState, _drawMode, *cIt, _mat);
// Process all children which are second pass
for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt)
if ((*cIt)->traverseMode() & SceneGraph::BaseNode::SecondPass)
traverseRenderableNodes( _glState, _drawMode, *cIt, _mat);
}
if (_node->status() != SceneGraph::BaseNode::HideNode )
_node->leave(*_glState, nodeDM);
}
}
}
int Renderer::cmpPriority(const void* _a, const void* _b)
{
const RenderObject* a = *(const RenderObject**)_a;
const RenderObject* b = *(const RenderObject**)_b;
return a->priority - b->priority;
}
void Renderer::render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties)
{
collectRenderObjects(_glState, _properties.drawMode(), PluginFunctions::getSceneGraphRootNode());
if (renderObjects_.empty())
return;
const size_t numRenderObjects = getNumRenderObjects();
// sort for priority
RenderObject** sortedObjects = new RenderObject*[numRenderObjects];
// init sorted objects
for (size_t i = 0; i < numRenderObjects; ++i)
{
sortedObjects[i] = &renderObjects_[i];
}
qsort(sortedObjects, numRenderObjects, sizeof(RenderObject*), cmpPriority);
// render
// gl cleanup
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_INDEX_ARRAY);
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
// clear back buffer
Vec4f clearColor = _properties.backgroundColor();
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
// log window remains hidden otherwise
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDrawBuffer(GL_BACK);
glDepthMask(1);
glColorMask(1,1,1,1);
glUseProgram(0);
glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
delete [] sortedObjects;
}
void Renderer::bindObjectVBO(ACG::RenderObject* _obj,
GLSL::Program* _prog)
{
_prog->use();
//////////////////////////////////////////////////////////////////////////
// NOTE:
// always bind buffers before glVertexAttribPointer calls!!
// freeze in glDrawElements guaranteed (with no error message whatsoever)
glBindBufferARB(GL_ARRAY_BUFFER_ARB, _obj->vertexBuffer);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _obj->indexBuffer);
// activate vertex declaration
_obj->vertexDecl->activateShaderPipeline(_prog);
}
void Renderer::bindObjectUniforms( ACG::RenderObject* _obj, GLSL::Program* _prog )
{
// transforms
GLMatrixf mvp = _obj->proj * _obj->modelview;
GLMatrixf mvIT = _obj->modelview;
mvIT.invert();
mvIT.transpose();
_prog->setUniform("g_mWVP", mvp);
_prog->setUniform("g_mWV", _obj->modelview);
_prog->setUniformMat3("g_mWVIT", mvIT);
_prog->setUniform("g_mP", _obj->proj);
// material
_prog->setUniform("g_cDiffuse", _obj->diffuse);
_prog->setUniform("g_cAmbient", _obj->ambient);
_prog->setUniform("g_cEmissive", _obj->emissive);
_prog->setUniform("g_cSpecular", _obj->specular);
Vec4f materialParams(_obj->shininess, _obj->alpha, 0.0f, 0.0f);
_prog->setUniform("g_vMaterial", materialParams);
// texture
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, _obj->texture);
_prog->setUniform("g_Texture0", 0);
// lights
for (int i = 0; i < numLights_; ++i)
{
SceneGraph::LightSource* lgt = lights_ + i;
ShaderGenLightType lgtType = lightTypes_[i];
#define V4toV3(v) (ACG::Vec3f(v[0], v[1], v[2]))
char szUniformName[256];
sprintf(szUniformName, "g_cLightDiffuse_%d", i);
_prog->setUniform(szUniformName, V4toV3(lgt->diffuseColor()));
sprintf(szUniformName, "g_cLightAmbient_%d", i);
_prog->setUniform(szUniformName, V4toV3(lgt->ambientColor()));
sprintf(szUniformName, "g_cLightSpecular_%d", i);
_prog->setUniform(szUniformName, V4toV3(lgt->specularColor()));
if (lgtType == SG_LIGHT_POINT || lgtType == SG_LIGHT_SPOT)
{
sprintf(szUniformName, "g_vLightPos_%d", i);
_prog->setUniform(szUniformName, Vec3f(lgt->position()));
Vec3f atten(lgt->constantAttenuation(),
lgt->linearAttenuation(), lgt->quadraticAttenuation());
sprintf(szUniformName, "g_vLightAtten_%d", i);
_prog->setUniform(szUniformName, atten);
}
if (lgtType == SG_LIGHT_DIRECTIONAL || lgtType == SG_LIGHT_SPOT)
{
sprintf(szUniformName, "g_vLightDir_%d", i);
_prog->setUniform(szUniformName, Vec3f(lgt->direction()));
}
if (lgtType == SG_LIGHT_SPOT)
{
Vec2f angleexp(lgt->spotCutoff(), lgt->spotExponent());
sprintf(szUniformName, "g_vLightAngleExp_%d", i);
_prog->setUniform(szUniformName, angleexp);
}
}
}
void Renderer::bindObjectRenderStates(ACG::RenderObject* _obj)
{
if (_obj->culling)
glEnable(GL_CULL_FACE);
else
glDisable(GL_CULL_FACE);
if (_obj->blending)
glEnable(GL_BLEND);
else
glDisable(GL_BLEND);
if (_obj->alphaTest)
glEnable(GL_ALPHA_TEST);
else
glDisable(GL_ALPHA_TEST);
if (_obj->depthTest)
glEnable(GL_DEPTH_TEST);
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]);
glDepthFunc(_obj->depthFunc);
// ACG::GLState::shadeModel(_obj->shadeModel);
glBlendFunc(_obj->blendSrc, _obj->blendDest);
}
void Renderer::drawObject(ACG::RenderObject* _obj)
{
// indexed drawing?
bool noIndices = true;
if (_obj->indexBuffer || _obj->sysmemIndexBuffer)
noIndices = false;
glPolygonMode(GL_FRONT_AND_BACK, _obj->fillMode);
if (noIndices)
glDrawArrays(_obj->primitiveMode, _obj->indexOffset, _obj->numIndices);
else
{
// ------------------------------------------
// index offset stuff not tested
int indexSize = 0;
switch (_obj->indexType)
{
case GL_UNSIGNED_INT: indexSize = 4; break;
case GL_UNSIGNED_SHORT: indexSize = 2; break;
default: indexSize = 1; break;
}
glDrawElements(_obj->primitiveMode, _obj->numIndices, _obj->indexType,
((const char*)_obj->sysmemIndexBuffer) + _obj->indexOffset * indexSize);
}
}
void Renderer::renderObject(ACG::RenderObject* _obj,
GLSL::Program* _prog,
bool _constRenderStates)