From 114a355274d6e600151b8d288d03b94ab5dde498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20M=C3=B6bius?= Date: Wed, 9 Jan 2013 16:52:19 +0000 Subject: [PATCH] Reorganize and document the shader renderer git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@16073 383ad7c9-94d9-4d36-a494-682f7c89f535 --- Renderer-Collect.cc | 187 +++++++++++++++++++++++++++++++++ Renderer.cc | 245 +++++--------------------------------------- Renderer.hh | 182 +++++++++++++++++++++----------- 3 files changed, 332 insertions(+), 282 deletions(-) create mode 100644 Renderer-Collect.cc diff --git a/Renderer-Collect.cc b/Renderer-Collect.cc new file mode 100644 index 0000000..8983062 --- /dev/null +++ b/Renderer-Collect.cc @@ -0,0 +1,187 @@ + +#include +#include + +#include "Renderer.hh" +#include +#include + +using namespace ACG; + +// ================================================= + +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; + + + // 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); + + + // fetch material (Node itself can be a material node, so we have to + // set that in front of the nodes own rendering + SceneGraph::MaterialNode* matNode = dynamic_cast(_node); + if (matNode) + _mat = &matNode->material(); + + if (_node->status() != SceneGraph::BaseNode::HideNode) + _node->getRenderObjects(this, *_glState, nodeDM, _mat); + + 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); + } + } +} + + +void Renderer::traverseLightNodes( ACG::SceneGraph::BaseNode* _node ) +{ + if (_node && numLights_ < SG_MAX_SHADER_LIGHTS) + { + BaseNode::StatusMode status(_node->status()); + bool process_children(status != BaseNode::HideChildren); + + // If the subtree is hidden, ignore this node and its children while rendering + if (status != BaseNode::HideSubtree) + { + + if (_node->status() != BaseNode::HideNode) + { + ACG::SceneGraph::LightNode* lnode = dynamic_cast(_node); + if (lnode) + { + ACG::SceneGraph::LightSource light; +// lnode->getLightSource(&light); + lnode->getLightSourceViewSpace(&light); + + // -------------------------- + // add light to renderer + + if (light.directional()) + lightTypes_[numLights_] = ACG::SG_LIGHT_DIRECTIONAL; + else if (light.spotCutoff() > 179.5f) + lightTypes_[numLights_] = ACG::SG_LIGHT_POINT; + else + lightTypes_[numLights_] = ACG::SG_LIGHT_SPOT; + + + lights_[numLights_] = light; + + ++numLights_; + + } + } + + if (process_children) + { + + BaseNode::ChildIter cIt, cEnd(_node->childrenEnd()); + + // Process all children which are not second pass + for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt) + if (~(*cIt)->traverseMode() & BaseNode::SecondPass) + traverseLightNodes(*cIt); + + // Process all children which are second pass + for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt) + if ((*cIt)->traverseMode() & BaseNode::SecondPass) + traverseLightNodes(*cIt); + + } + + } + } +} + + +void Renderer::collectLightNodes( ACG::SceneGraph::BaseNode* _node ) +{ + numLights_ = 0; + traverseLightNodes(_node); +} + diff --git a/Renderer.cc b/Renderer.cc index f52564a..fd9de19 100644 --- a/Renderer.cc +++ b/Renderer.cc @@ -27,126 +27,11 @@ Renderer::Renderer() 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; - - - // 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); - - - // fetch material (Node itself can be a material node, so we have to - // set that in front of the nodes own rendering - SceneGraph::MaterialNode* matNode = dynamic_cast(_node); - if (matNode) - _mat = &matNode->material(); - - if (_node->status() != SceneGraph::BaseNode::HideNode) - _node->getRenderObjects(this, *_glState, nodeDM, _mat); - - 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; @@ -155,47 +40,49 @@ int Renderer::cmpPriority(const void* _a, const void* _b) return a->priority - b->priority; } - - void Renderer::render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties) { + // First, all render objects get collected. collectRenderObjects(_glState, _properties.drawMode(), PluginFunctions::getSceneGraphRootNode()); + // Check if there is anything to render if (renderObjects_.empty()) return; - const size_t numRenderObjects = getNumRenderObjects(); + // ========================================================== + // Sort renderable objects based on their priority + // ========================================================== + const size_t numRenderObjects = renderObjects_.size(); // 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); - // dumpRenderObjectsToText("../../dump_ro.txt", sortedObjects); + // ========================================================== + // Now we render them + // ========================================================== - // render - + // --------------------------- + // Initialize the render state + // --------------------------- // gl cleanup - glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_INDEX_ARRAY); - // size of a rendered point is set in vertex-shader via gl_PointSize -#ifndef __APPLE__ - glEnable(GL_PROGRAM_POINT_SIZE_ARB); -#endif + #ifndef __APPLE__ + glEnable(GL_PROGRAM_POINT_SIZE_ARB); + #endif glEnable(GL_CULL_FACE); glEnable(GL_DEPTH_TEST); @@ -207,11 +94,15 @@ 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); + // --------------------------- + // Render objects one by one + // --------------------------- for (size_t i = 0; i < numRenderObjects; ++i) renderObject(sortedObjects[i]); - - // restore common opengl state + // ---------------------------------------- + // Restore common opengl state + // ---------------------------------------- // log window remains hidden otherwise glBindFramebuffer(GL_FRAMEBUFFER, 0); @@ -225,9 +116,6 @@ void Renderer::render(ACG::GLState* _glState, Viewer::ViewerProperties& _propert glBindBufferARB(GL_ARRAY_BUFFER_ARB, 0); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); - - - delete [] sortedObjects; } @@ -245,7 +133,6 @@ void Renderer::bindObjectVBO(ACG::RenderObject* _obj, glBindBufferARB(GL_ARRAY_BUFFER_ARB, _obj->vertexBuffer); glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, _obj->indexBuffer); - // activate vertex declaration _obj->vertexDecl->activateShaderPipeline(_prog); } @@ -409,7 +296,6 @@ void Renderer::renderObject(ACG::RenderObject* _obj, // select shader from cache GLSL::Program* prog = _prog ? _prog : ShaderCache::getInstance()->getProgram(&_obj->shaderDesc); - bindObjectVBO(_obj, prog); // --------------------------------------- @@ -435,91 +321,6 @@ void Renderer::renderObject(ACG::RenderObject* _obj, } - - - - - -void Renderer::traverseLightNodes( ACG::SceneGraph::BaseNode* _node ) -{ - if (_node && numLights_ < SG_MAX_SHADER_LIGHTS) - { - BaseNode::StatusMode status(_node->status()); - bool process_children(status != BaseNode::HideChildren); - - // If the subtree is hidden, ignore this node and its children while rendering - if (status != BaseNode::HideSubtree) - { - - if (_node->status() != BaseNode::HideNode) - { - ACG::SceneGraph::LightNode* lnode = dynamic_cast(_node); - if (lnode) - { - ACG::SceneGraph::LightSource light; -// lnode->getLightSource(&light); - lnode->getLightSourceViewSpace(&light); - - // -------------------------- - // add light to renderer - - if (light.directional()) - lightTypes_[numLights_] = ACG::SG_LIGHT_DIRECTIONAL; - else if (light.spotCutoff() > 179.5f) - lightTypes_[numLights_] = ACG::SG_LIGHT_POINT; - else - lightTypes_[numLights_] = ACG::SG_LIGHT_SPOT; - - - lights_[numLights_] = light; - - ++numLights_; - - - - - - - } - } - - if (process_children) - { - - BaseNode::ChildIter cIt, cEnd(_node->childrenEnd()); - - // Process all children which are not second pass - for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt) - if (~(*cIt)->traverseMode() & BaseNode::SecondPass) - traverseLightNodes(*cIt); - - // Process all children which are second pass - for (cIt = _node->childrenBegin(); cIt != cEnd; ++cIt) - if ((*cIt)->traverseMode() & BaseNode::SecondPass) - traverseLightNodes(*cIt); - - } - - } - } -} - - -void Renderer::collectLightNodes( ACG::SceneGraph::BaseNode* _node ) -{ - numLights_ = 0; - traverseLightNodes(_node); -} - -int Renderer::getNumRenderObjects() const -{ - return renderObjects_.size(); -} - - - - - QString Renderer::checkOpenGL() { return QString(""); @@ -531,7 +332,9 @@ void Renderer::dumpRenderObjectsToText(const char* _fileName, RenderObject** _so if (fileOut.open(QFile::WriteOnly | QFile::Truncate)) { QTextStream outStrm(&fileOut); - for (int i = 0; i < getNumRenderObjects(); ++i) + const int numRenderObjects = renderObjects_.size(); + + for (int i = 0; i < numRenderObjects; ++i) { if (_sortedList) outStrm << "\n" << _sortedList[i]->toString(); diff --git a/Renderer.hh b/Renderer.hh index 51f3087..9141ae0 100644 --- a/Renderer.hh +++ b/Renderer.hh @@ -60,6 +60,11 @@ #include +/** \brief A simple renderer Example for the shader pipeline + * + * It has to derive from ACG::IRenderer as the nodes will will pass back the generated render objects + * via this objects addRenderObject() function. + */ class Renderer : public QObject, BaseInterface, RenderInterface, LoggingInterface, ACG::IRenderer { Q_OBJECT @@ -94,110 +99,165 @@ private slots: void render(ACG::GLState* _glState, Viewer::ViewerProperties& _properties); QString rendererName() {return QString("Alpha_Version_ShaderPipeline");} void supportedDrawModes(ACG::SceneGraph::DrawModes::DrawMode& _mode) {_mode = ACG::SceneGraph::DrawModes::DEFAULT;} - QString checkOpenGL(); +//========================================================================= +// Callback for the scenegraph nodes +//========================================================================= public: + /** \brief callback for the nodes, which send new render objects via this function. + * + * AddRenderObject is typically called by a scenegraph nodes during the collection of renderable + * objects. + * + * A renderobject is a collection of opengl states, buffers and parameters, that correspond to exactly one draw call. + */ + virtual void addRenderObject(ACG::RenderObject* _renderObject); - /** - Traverses the scenegraph and calls the getRenderObject function of each node. - Each node can then add multiple renderobjects via addRenderObject to this renderer. - Also collects all light sources in the scenegraph. +//========================================================================= +// Render object collection +//========================================================================= +private: - The currently active list of renderobjects is invalidated too. - */ + /** \brief Traverse the scenegraph to collect render information + * + * Traverses the scenegraph and calls the getRenderObject function of each node. + * Each node can then add multiple renderobjects via addRenderObject to this renderer. + * + * Also collects all light sources in the scenegraph. + * The currently active list of renderobjects is invalidated too. + */ void collectRenderObjects(ACG::GLState* _glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode* _sceneGraphRoot); - /** - addRenderObject is typically called by a scenegraph node. - A renderobject is a collection of opengl states, buffers and parameters, - that correspond to exactly one draw call. - */ - virtual void addRenderObject(ACG::RenderObject* _renderObject); + /** \brief Scene graph traversal for render object collection + * + * Calls getRenderObjects on each node of the scenegraph recursively. + */ + void traverseRenderableNodes( ACG::GLState* _glState, + ACG::SceneGraph::DrawModes::DrawMode _drawMode, + ACG::SceneGraph::BaseNode* _node, + const ACG::SceneGraph::Material* _mat); -protected: +//========================================================================= +// Light node collection +//========================================================================= +private: - - /** - compare function for qsort - */ - static int cmpPriority(const void*, const void*); + /** \brief Find all light sources in the scene + * + * Find all light nodes in the scene and save them for the next render() call. + * + * The lights are collected in lights_ while the corresponding type ends up in lightTypes_ + */ + virtual void collectLightNodes(ACG::SceneGraph::BaseNode* _node); + + /** \brief Light Node traverser + * + * Finds all Light Nodes in the scenegraph and stores them for later use. This is a recursive function. + */ + void traverseLightNodes(ACG::SceneGraph::BaseNode* _node); - /** Find all light nodes in the scene and save them for the next render() call. - Implemention is not possible here: SceneGraph::LightSource is not defined yet - */ - virtual void collectLightNodes(ACG::SceneGraph::BaseNode* _node); +//========================================================================= +// Sorting +//========================================================================= +private: - /** Calls getRenderObjects on each node of the scenegraph recursively. + /** \brief Compare priority of render objects + * + * compare function for qsort. This is required to compare render objects based + * on their prioerity and render them in the right order */ - void traverseRenderableNodes(ACG::GLState* _glState, ACG::SceneGraph::DrawModes::DrawMode _drawMode, ACG::SceneGraph::BaseNode* _node, const ACG::SceneGraph::Material* _mat); + static int cmpPriority(const void*, const void*); +//========================================================================= +// Rendering +//========================================================================= +private: - /** - Bind vertex, index buffer and vertex format of a render object. - */ + /** \brief Binding VBOs (First state function) + * + * This is the first function called by renderObject(). + * + * It binds vertex, index buffer and vertex format of a + * render object. + * + */ virtual void bindObjectVBO(ACG::RenderObject* _obj, GLSL::Program* _prog); - /** - Set common shader constants like model-view-projection matrix, - material colors and light params. - */ + /** \brief Binding Uniforms (Second state function) + * + * This is the second function called by renderObject(). + * + * Set common shader constants like model-view-projection matrix, + * material colors and light params. + */ virtual void bindObjectUniforms(ACG::RenderObject* _obj, GLSL::Program* _prog); - /** - Prepare the opengl state machine for a renderobject draw call. - This includes any glEnable/glDisable states, depth-cmp functions, blend equation.. - */ + + /** \brief Binding Render state (Third state function) + * + * This is the third function called by renderObject(). + * + * Prepare the opengl state machine for a renderobject draw call. + * + * This includes any glEnable/glDisable states, depth-cmp functions, blend equation.. + */ virtual void bindObjectRenderStates(ACG::RenderObject* _obj); - /** - Executes the opengl draw call. - */ + /** \brief Executes the opengl draw call for one object (Fourth function) + * + * This is the fourth function called by renderObject(). + * + * Executes one draw call for the given render object + */ virtual void drawObject(ACG::RenderObject* _obj); - - /** - Fully prepares opengl for a renderobject and executes the draw call. - This combines bindObjectVBO, bindObjectUniforms... - Optionally render-states may not be changed, in case depth-peeling or - similar global shader operations may require a fixed state setting. + /** \brief Render one render object + * + * Fully prepares opengl for a renderobject and executes the draw call. + * This combines bindObjectVBO, bindObjectUniforms... + * + * Optionally render-states may not be changed, in case depth-peeling or + * similar global shader operations may require a fixed state setting. */ virtual void renderObject(ACG::RenderObject* _obj, GLSL::Program* _prog = 0, bool _constRenderStates = false); + //========================================================================= + // Debugging + //========================================================================= +private: - /** \brief Light Node traverser + /** \brief Debugging function to dump list of render objects into a file * - * Finds all Light Nodes in the scenegraph and stores them for later use. + * Dump list of render objects to text file. + * @param _fileName name of text file to write to + * @param _sortedList dump sorted render objects in order, may be 0 to use the unsorted list instead */ - void traverseLightNodes(ACG::SceneGraph::BaseNode* _node); - - - int getNumRenderObjects() const; - - - /** - Dump list of render objects to text file. - @param _fileName name of text file to write to - @param _sortedList dump sorted render objects in order, may be 0 to use the unsorted list instead - */ void dumpRenderObjectsToText(const char* _fileName, ACG::RenderObject** _sortedList = 0) const; + //========================================================================= + // Variables + //========================================================================= +private: - - /// lighting setup + /// Current number of lights (Filled by collectLightNodes) int numLights_; + + /// Light sources (Filled by collectLightNodes) ACG::SceneGraph::LightSource lights_[SG_MAX_SHADER_LIGHTS]; + + /// Type of light sources (Filled by collectLightNodes) ACG::ShaderGenLightType lightTypes_[SG_MAX_SHADER_LIGHTS]; - /// array of renderobjects, filled by addRenderObject + /// Array of renderobjects (Filled by addRenderObject) std::vector renderObjects_; -- GitLab