Commit 44cca6c7 authored by Jan Möbius's avatar Jan Möbius
Browse files

Shadercache, renderer and shadergenerator updates

Skeleton support for renderer

refs #901

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@15660 383ad7c9-94d9-4d36-a494-682f7c89f535
parent d27e5e26
......@@ -51,8 +51,17 @@
#include <ACG/GL/VertexDeclaration.hh>
#include <ACG/GL/GLState.hh>
#include <ACG/Scenegraph/DrawModes.hh>
void ACG::RenderObject::initFromState( GLState* _glState )
namespace ACG
{
using namespace SceneGraph;
void RenderObject::initFromState( GLState* _glState )
{
culling = true;
blending = false;
......@@ -70,6 +79,8 @@ void ACG::RenderObject::initFromState( GLState* _glState )
blendSrc = GL_ONE;
blendDest = GL_ZERO;
alpha = 1.0f;
if (_glState)
{
modelview = _glState->modelview();
......@@ -103,7 +114,38 @@ void ACG::RenderObject::initFromState( GLState* _glState )
}
}
ACG::RenderObject::RenderObject()
void RenderObject::setupShaderGenFromDrawmode( const DrawModes::DrawModeProperties* _props )
{
if (_props)
{
shaderDesc.vertexColors = _props->colored();
shaderDesc.textured = _props->textured();
shaderDesc.numLights = _props->lighting() ? 0 : -1;
switch (_props->lightStage())
{
case DrawModes::LIGHTSTAGE_SMOOTH: shaderDesc.shadeMode = SG_SHADE_GOURAUD; break;;
case DrawModes::LIGHTSTAGE_PHONG: shaderDesc.shadeMode = SG_SHADE_PHONG; break;;
case DrawModes::LIGHTSTAGE_UNLIT: shaderDesc.shadeMode = SG_SHADE_UNLIT; break;;
default: break;
}
if (_props->flatShaded())
shaderDesc.shadeMode = SG_SHADE_FLAT;
if (_props->primitive() == DrawModes::PRIMITIVE_WIREFRAME ||
_props->primitive() == DrawModes::PRIMITIVE_HIDDENLINE ||
_props->primitive() == DrawModes::PRIMITIVE_EDGE ||
_props->primitive() == DrawModes::PRIMITIVE_HALFEDGE)
shaderDesc.shadeMode = SG_SHADE_UNLIT;
}
}
RenderObject::RenderObject()
{
memset(this, 0, sizeof(RenderObject));
}
\ No newline at end of file
}
} // namespace ACG end
\ No newline at end of file
......@@ -50,9 +50,18 @@
namespace ACG
{
// forward declaration
class VertexDeclaration;
class GLState;
namespace SceneGraph {
namespace DrawModes {
class DrawModeProperties;
}
}
/** \brief Interface class between scenegraph and renderer
*
* RenderObject is the primary interface between scenegraph and renderer.
......@@ -193,7 +202,6 @@ struct ACGDLLEXPORT RenderObject
shininess;
/** \brief Texture to be used
*
* eventually a more flexible texture system with user defined:
......@@ -208,6 +216,8 @@ struct ACGDLLEXPORT RenderObject
/// used internally for renderer debugging
int debugID;
/// may be used internally by the renderer
unsigned int internalFlags_;
// opengl style helper function interface:
......@@ -249,6 +259,10 @@ struct ACGDLLEXPORT RenderObject
* Grabs material and transforms automatically if a GLState is provided.
*/
void initFromState(GLState* _glState);
/** \brief Fills out ShaderGenDesc parameters based on Drawmode properties
*/
void setupShaderGenFromDrawmode(const SceneGraph::DrawModes::DrawModeProperties* _props);
};
......@@ -267,7 +281,6 @@ public:
*/
virtual void addRenderObject(RenderObject* _renderObject) = 0;
protected:
};
......
......@@ -86,17 +86,22 @@ ShaderCache* ACG::ShaderCache::getInstance()
// - modify compareShaderGenDescs s.t. it defines an order
// or generate a hash key from ShaderGenDesc
GLSL::Program* ACG::ShaderCache::getProgram( const ShaderGenDesc* _desc )
GLSL::Program* ACG::ShaderCache::getProgram( const ShaderGenDesc* _desc, unsigned int _usage )
{
CacheEntry newEntry;
newEntry.desc = *_desc;
newEntry.usage = _usage;
for (CacheList::iterator it = cache_.begin(); it != cache_.end(); ++it)
{
if (!compareShaderGenDescs(&it->first, _desc))
if (!compareShaderGenDescs(&it->first, &newEntry))
return it->second;
}
// glsl program not in cache, generate shaders
ShaderProgGenerator progGen(_desc);
ShaderProgGenerator progGen(_desc, _usage);
#ifdef SG_DEBUG_OUTPUT
progGen.saveFragmentShToFile("../../../dbg_frag.glsl");
......@@ -121,36 +126,41 @@ GLSL::Program* ACG::ShaderCache::getProgram( const ShaderGenDesc* _desc )
prog->link();
glCheckErrors();
cache_.push_back(std::pair<ShaderGenDesc, GLSL::Program*>(*_desc, prog));
cache_.push_back(std::pair<CacheEntry, GLSL::Program*>(newEntry, prog));
return prog;
}
int ACG::ShaderCache::compareShaderGenDescs( const ShaderGenDesc* _a, const ShaderGenDesc* _b )
int ACG::ShaderCache::compareShaderGenDescs( const CacheEntry* _a, const CacheEntry* _b )
{
if (_a->numLights != _b->numLights)
if (_a->usage != _b->usage)
return -1;
const ShaderGenDesc* a = &_a->desc;
const ShaderGenDesc* b = &_b->desc;
if (a->numLights != b->numLights)
return -1;
if (_a->shadeMode != _b->shadeMode)
if (a->shadeMode != b->shadeMode)
return -1;
if (_a->vertexColors != _b->vertexColors)
if (a->vertexColors != b->vertexColors)
return -1;
if (_a->textured != _b->textured)
if (a->textured != b->textured)
return -1;
if (_a->vertexTemplateFile != _b->vertexTemplateFile)
if (a->vertexTemplateFile != b->vertexTemplateFile)
return -1;
if (_a->fragmentTemplateFile != _b->fragmentTemplateFile)
if (a->fragmentTemplateFile != b->fragmentTemplateFile)
return -1;
if (_a->numLights)
return memcmp(_a->lightTypes, _b->lightTypes, _a->numLights * sizeof(ShaderGenLightType));
if (a->numLights)
return memcmp(a->lightTypes, b->lightTypes, a->numLights * sizeof(ShaderGenLightType));
return 0;
}
......
......@@ -45,6 +45,7 @@
#include <list>
#include <ACG/Config/ACGDefines.hh>
#include <ACG/GL/ShaderGenerator.hh>
// forward declaration
namespace GLSL
......@@ -55,8 +56,6 @@ namespace GLSL
namespace ACG {
struct ShaderGenDesc;
/** \brief Cache for shaders
*
......@@ -75,16 +74,23 @@ public:
static ShaderCache* getInstance();
GLSL::Program* getProgram(const ShaderGenDesc* _desc);
GLSL::Program* getProgram(const ShaderGenDesc* _desc, unsigned int _usage = 0);
protected:
ShaderCache();
int compareShaderGenDescs(const ShaderGenDesc* _a, const ShaderGenDesc* _b);
struct CacheEntry
{
ShaderGenDesc desc;
unsigned int usage;
};
int compareShaderGenDescs(const CacheEntry* _a, const CacheEntry* _b);
typedef std::list<std::pair<ShaderGenDesc, GLSL::Program*> > CacheList;
typedef std::list<std::pair<CacheEntry, GLSL::Program*> > CacheList;
CacheList cache_;
};
......
......@@ -55,9 +55,15 @@
namespace ACG
{
#define LIGHTING_CODE_FILE "ShaderGen/SG_LIGHTING.GLSL"
#define LIGHTING_CODE_FILE "ShaderGen/SG_LIGHTING.GLSL"
int ShaderProgGenerator::numModifiers_ = 0;
ShaderModifier* ShaderProgGenerator::modifiers_[32] = {0};
ShaderGenerator::ShaderGenerator()
......@@ -74,6 +80,8 @@ ShaderGenerator::~ShaderGenerator()
void ShaderGenerator::initVertexShaderIO(const ShaderGenDesc* _desc)
{
addInput("vec4 inPosition");
addOutput("vec4 outPosCS");
if (_desc->shadeMode != SG_SHADE_UNLIT)
addInput("vec3 inNormal");
......@@ -116,6 +124,7 @@ void ShaderGenerator::initFragmentShaderIO(const ShaderGenDesc* _desc)
if (_desc->textured)
addInput("vec2 outTexCoord");
addInput("vec4 outPosCS");
std::string strColorOut = "";
......@@ -346,8 +355,9 @@ const QStringList& ShaderGenerator::getShaderCode()
QString ShaderProgGenerator::shaderDir_;
QStringList ShaderProgGenerator::lightingCode_;
ShaderProgGenerator::ShaderProgGenerator(const ShaderGenDesc* _desc)
: vertex_(0), fragment_(0)
ShaderProgGenerator::ShaderProgGenerator(const ShaderGenDesc* _desc,
unsigned int _usage)
: vertex_(0), fragment_(0), usage_(_usage)
{
if (shaderDir_.isEmpty())
std::cout << "error: call ShaderProgGenerator::setShaderDir() first!" << std::endl;
......@@ -457,10 +467,18 @@ void ShaderProgGenerator::buildVertexShader()
// vertex_->initDefaultVertexShaderIO();
vertex_->initVertexShaderIO(&desc_);
vertex_->initDefaultUniforms();
// apply i/o modifiers
for (int i = 0; i < numModifiers_; ++i)
{
if (usage_ & (1 << i))
modifiers_[i]->modifyVertexIO(vertex_);
}
initGenDefines(vertex_);
......@@ -555,12 +573,20 @@ void ShaderProgGenerator::addVertexBeginCode(QStringList* _code)
}
// apply modifiers
for (int i = 0; i < numModifiers_; ++i)
{
if (usage_ & (1 << i))
modifiers_[i]->modifyVertexBeginCode(_code);
}
}
void ShaderProgGenerator::addVertexEndCode(QStringList* _code)
{
_code->push_back("gl_Position = sg_vPosPS;");
_code->push_back("outPosCS = sg_vPosPS;");
if (desc_.textured)
_code->push_back("outTexCoord = sg_vTexCoord;");
......@@ -575,6 +601,15 @@ void ShaderProgGenerator::addVertexEndCode(QStringList* _code)
_code->push_back("outNormal = sg_vNormalVS;");
_code->push_back("outPosVS = sg_vPosVS;");
}
// apply modifiers
for (int i = 0; i < numModifiers_; ++i)
{
if (usage_ & (1 << i))
modifiers_[i]->modifyVertexEndCode(_code);
}
}
......@@ -608,6 +643,7 @@ void ShaderProgGenerator::buildFragmentShader()
fragment_->initFragmentShaderIO(&desc_);
fragment_->initDefaultUniforms();
......@@ -615,6 +651,13 @@ void ShaderProgGenerator::buildFragmentShader()
if (desc_.textured)
fragment_->addUniform("sampler2D g_Texture0");
// apply i/o modifiers
for (int i = 0; i < numModifiers_; ++i)
{
if (usage_ & (1 << i))
modifiers_[i]->modifyFragmentIO(fragment_);
}
initGenDefines(fragment_);
......@@ -688,6 +731,16 @@ void ShaderProgGenerator::buildFragmentShader()
void ShaderProgGenerator::addFragmentBeginCode(QStringList* _code)
{
// support for projective texture mapping
_code->push_back("vec2 sg_vScreenPos = outPosCS.xy / outPosCS.w * 0.5 + vec2(0.5, 0.5);");
// apply modifiers
for (int i = 0; i < numModifiers_; ++i)
{
if (usage_ & (1 << i))
modifiers_[i]->modifyFragmentBeginCode(_code);
}
_code->push_back("vec4 sg_cColor = vec4(g_cEmissive, ALPHA);");
if (desc_.shadeMode == SG_SHADE_GOURAUD ||
......@@ -714,6 +767,13 @@ void ShaderProgGenerator::addFragmentBeginCode(QStringList* _code)
void ShaderProgGenerator::addFragmentEndCode(QStringList* _code)
{
_code->push_back("outFragment = sg_cColor;");
// apply modifiers
for (int i = 0; i < numModifiers_; ++i)
{
if (usage_ & (1 << i))
modifiers_[i]->modifyFragmentEndCode(_code);
}
}
......@@ -810,7 +870,36 @@ void ShaderProgGenerator::setShaderDir( QString _dir )
shaderDir_ = _dir;
}
unsigned int ShaderProgGenerator::registerModifier( ShaderModifier* _modifier )
{
if (!_modifier) return 0;
// redundancy check
for (unsigned int i = 0; i < 32; ++i)
{
if (modifiers_[i] == _modifier)
return i;
}
if (numModifiers_ == 32)
return 0;
modifiers_[numModifiers_++] = _modifier;
_modifier->modifierID_ = (unsigned int)numModifiers_;
return _modifier->modifierID_;
}
//=============================================================================
ShaderModifier::ShaderModifier( void )
: modifierID_(0)
{}
ShaderModifier::~ShaderModifier( void )
{}
} // namespace ACG
//=============================================================================
......@@ -205,6 +205,36 @@ private:
ShaderProgGenerator is responsible for generating a matching pair of vertex and fragment shaders.
*/
// A shader modifier can modify uniforms, in/outputs
// and glsl code of vertex and fragment shaders.
// This is useful for global effects like shadow mapping
// and depth peeling, where only a little changes in code are necessary.
class ACGDLLEXPORT ShaderModifier
{
friend class ShaderProgGenerator;
public:
ShaderModifier(void);
virtual ~ShaderModifier(void);
virtual void modifyVertexIO(ShaderGenerator* _shader) {}
virtual void modifyVertexBeginCode(QStringList* _code) {}
virtual void modifyVertexEndCode(QStringList* _code) {}
virtual void modifyFragmentIO(ShaderGenerator* _shader) {}
virtual void modifyFragmentBeginCode(QStringList* _code) {}
virtual void modifyFragmentEndCode(QStringList* _code) {}
unsigned int getID() {return modifierID_;}
operator unsigned int() const {return modifierID_;}
private:
unsigned int modifierID_;
};
class ACGDLLEXPORT ShaderProgGenerator
{
public:
......@@ -215,8 +245,7 @@ public:
*/
static void setShaderDir(QString _dir);
ShaderProgGenerator(const ShaderGenDesc* _desc);
ShaderProgGenerator(const ShaderGenDesc* _desc, unsigned int _modifierFlags = 0);
virtual ~ShaderProgGenerator(void);
......@@ -231,6 +260,10 @@ public:
*/
const QStringList& getFragmentShaderCode();
static unsigned int registerModifier(ShaderModifier* _modifier);
private:
/** \brief Loads external shader templates
......@@ -279,7 +312,13 @@ private:
QStringList vertexTemplate_;
QStringList fragmentTemplate_;
ShaderGenDesc desc_;
ShaderGenDesc desc_;
unsigned int usage_;
/// registered shader modifier
static int numModifiers_;
static ShaderModifier* modifiers_[32];
/// path + filename to shader templates
QString vertexShaderFile_;
......@@ -288,6 +327,8 @@ private:
static QString shaderDir_;
static QStringList lightingCode_;
};
......
......@@ -55,6 +55,7 @@
#include "SkeletonNodeT.hh"
#include <ACG/GL/gl.hh>
#include <ACG/GL/IRenderer.hh>
#include <vector>
#include <deque>
......@@ -644,6 +645,56 @@ void SkeletonNodeT<SkeletonType>::draw_bone(GLState &_state, DrawModes::DrawMode
}
//----------------------------------------------------------------------------
/** \brief Helper function to create a renderobject for bones
*
*/
template <class SkeletonType>
void SkeletonNodeT<SkeletonType>::addBoneToRenderer(IRenderer* _renderer, RenderObject& _base, const Point& _parent, const Point& _axis)
{
// save previous modelview transform
GLMatrixf prevTransform = _base.modelview;
Point midPoint = _parent + 0.1 * _axis;
_base.modelview.translate(midPoint[0], midPoint[1], midPoint[2]);
Point direction = _axis;
Point z_axis(0,0,1);
Point rot_normal;
double rot_angle;
direction.normalize();
rot_angle = acos((z_axis | direction))*180/M_PI;
rot_normal = ((z_axis % direction).normalize());
if(fabs(rot_angle) > 0.0001 && fabs(180-rot_angle) > 0.0001)
_base.modelview.rotate(rot_angle, rot_normal[0], rot_normal[1], rot_normal[2]);
else
_base.modelview.rotate(rot_angle, 1, 0, 0);
double boneLength = _axis.norm();
double radius = boneLength * 0.07;
//draw the large cone from midPoint to the end of the bone
cone_->setBottomRadius(1.0f);
cone_->setTopRadius(0.0f);
_base.modelview.scale(radius, radius, 1.0f);
cone_->addToRenderer(_renderer, &_base, boneLength*0.9);
//rotate 180.0 and draw the the small cone from midPoint to the start
_base.modelview.rotate(180.0, 1, 0, 0);
cone_->addToRenderer(_renderer, &_base, boneLength*0.1);
_base.modelview = prevTransform;
}
//----------------------------------------------------------------------------
/**
......@@ -694,6 +745,106 @@ bool SkeletonNodeT<SkeletonType>::coordFramesVisible()
}
//----------------------------------------------------------------------------
/**
* @brief Generates renderobjects instead of direct draw calls for better rendering management.
*/
template <class SkeletonType>
void SkeletonNodeT<SkeletonType>::getRenderObjects(IRenderer* _renderer,
GLState& _state,
const DrawModes::DrawMode& _drawMode)
{
RenderObject ro;
ro.initFromState(&_state);
// render states
ro.depthTest = true;
ro.depthWrite = true;
ro.culling = true;
ro.blending = false;
Pose *pose = skeleton_.pose(hAni_);
typename SkeletonType::Iterator it;
// draw bones
//
// if ( (_drawMode == DrawModes::WIREFRAME)
// || (_drawMode == DrawModes::SOLID_FLAT_SHADED)
// || (_drawMode == DrawModes::SOLID_FACES_COLORED)
// || (_drawMode == DrawModes::SOLID_FACES_COLORED_FLAT_SHADED) )
{
Vec4f baseColor = _state.base_color();
ro.setupShaderGenFromDrawmode(_drawMode.getDrawModeProperties());
// draw the bones
for(it = skeleton_.begin(); it != skeleton_.end(); ++it) {
//joint is the (unique) tail joint of the bone
Joint* joint = *it;
Joint* parent = joint->parent();
// root can be ignored
// we only want to draw bones from (parent -> joint)
if (parent == 0)
continue;