From Maciej Krol, "As promised to Roland I assembled simple shader generator. ShaderGenVisitor converts accumulated fixed function pipeline state sets to ones with shader programs. Generated state sets are attached to geometries and stored in ShaderGenCache for reuse.
Very simple cases of state configuration are supported (all the ones I really need): - single per pixel not attenuated non spot light source ON/OFF - exp2 fog ON/OFF - diffuse texture in rgb + optional specular gloss in alpha (Texture unit 0) ON/OFF - normal map texture (Texture unit 1 and Tangent in VertexAttribArray 6) ON/OFF - blending and alpha testing (not in shader pipeline) To view fixed function pipeline files and paged databases simply run >osgshadergen myfile.osg"
This commit is contained in:
parent
ffbed2b222
commit
1fd5eefbcf
@ -85,6 +85,7 @@ IF(DYNAMIC_OPENSCENEGRAPH)
|
||||
ADD_SUBDIRECTORY(osgscribe)
|
||||
ADD_SUBDIRECTORY(osgsequence)
|
||||
ADD_SUBDIRECTORY(osgshaders)
|
||||
ADD_SUBDIRECTORY(osgshadergen)
|
||||
ADD_SUBDIRECTORY(osgshaderterrain)
|
||||
ADD_SUBDIRECTORY(osgshadow)
|
||||
ADD_SUBDIRECTORY(osgshape)
|
||||
|
6
examples/osgshadergen/CMakeLists.txt
Normal file
6
examples/osgshadergen/CMakeLists.txt
Normal file
@ -0,0 +1,6 @@
|
||||
#this file is automatically generated
|
||||
|
||||
|
||||
SET(TARGET_SRC osgshadergen.cpp )
|
||||
#### end var setup ###
|
||||
SETUP_EXAMPLE(osgshadergen)
|
167
examples/osgshadergen/osgshadergen.cpp
Normal file
167
examples/osgshadergen/osgshadergen.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
||||
*
|
||||
* This application is open source and may be redistributed and/or modified
|
||||
* freely and without restriction, both in commericial and non commericial applications,
|
||||
* as long as this copyright notice is maintained.
|
||||
*
|
||||
* This application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#include <osgDB/ReadFile>
|
||||
#include <osgUtil/ShaderGen>
|
||||
|
||||
#include <osgViewer/Viewer>
|
||||
#include <osgViewer/ViewerEventHandlers>
|
||||
|
||||
#include <osgGA/TrackballManipulator>
|
||||
#include <osgGA/FlightManipulator>
|
||||
#include <osgGA/DriveManipulator>
|
||||
#include <osgGA/KeySwitchMatrixManipulator>
|
||||
#include <osgGA/StateSetManipulator>
|
||||
#include <osgGA/AnimationPathManipulator>
|
||||
#include <osgGA/TerrainManipulator>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
||||
class ShaderGenReadFileCallback : public osgDB::Registry::ReadFileCallback
|
||||
{
|
||||
public:
|
||||
ShaderGenReadFileCallback()
|
||||
{
|
||||
}
|
||||
|
||||
virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& filename, const osgDB::ReaderWriter::Options* options)
|
||||
{
|
||||
osgDB::ReaderWriter::ReadResult result = osgDB::Registry::ReadFileCallback::readNode(filename, options);
|
||||
if (osg::Node *node = result.getNode())
|
||||
{
|
||||
_visitor.reset();
|
||||
node->accept(_visitor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void setRootStateSet(osg::StateSet *stateSet) { _visitor.setRootStateSet(stateSet); }
|
||||
osg::StateSet *getRootStateSet() const { return _visitor.getRootStateSet(); }
|
||||
|
||||
protected:
|
||||
osgUtil::ShaderGenVisitor _visitor;
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
// use an ArgumentParser object to manage the program arguments.
|
||||
osg::ArgumentParser arguments(&argc,argv);
|
||||
|
||||
arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
|
||||
arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+
|
||||
" is an example of conversion of fixed function pipeline to GLSL");
|
||||
arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ...");
|
||||
|
||||
osgViewer::Viewer viewer(arguments);
|
||||
|
||||
unsigned int helpType = 0;
|
||||
if ((helpType = arguments.readHelpType()))
|
||||
{
|
||||
arguments.getApplicationUsage()->write(std::cout, helpType);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// report any errors if they have occurred when parsing the program arguments.
|
||||
if (arguments.errors())
|
||||
{
|
||||
arguments.writeErrorMessages(std::cout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (arguments.argc()<=1)
|
||||
{
|
||||
arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// set up the camera manipulators.
|
||||
{
|
||||
osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
|
||||
|
||||
keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
|
||||
keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
|
||||
keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
|
||||
keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
|
||||
|
||||
std::string pathfile;
|
||||
char keyForAnimationPath = '5';
|
||||
while (arguments.read("-p",pathfile))
|
||||
{
|
||||
osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
|
||||
if (apm || !apm->valid())
|
||||
{
|
||||
unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
|
||||
keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm );
|
||||
keyswitchManipulator->selectMatrixManipulator(num);
|
||||
++keyForAnimationPath;
|
||||
}
|
||||
}
|
||||
|
||||
viewer.setCameraManipulator( keyswitchManipulator.get() );
|
||||
}
|
||||
|
||||
// add the state manipulator
|
||||
viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
|
||||
|
||||
// add the thread model handler
|
||||
viewer.addEventHandler(new osgViewer::ThreadingHandler);
|
||||
|
||||
// add the window size toggle handler
|
||||
viewer.addEventHandler(new osgViewer::WindowSizeHandler);
|
||||
|
||||
// add the stats handler
|
||||
viewer.addEventHandler(new osgViewer::StatsHandler);
|
||||
|
||||
// add the help handler
|
||||
viewer.addEventHandler(new osgViewer::HelpHandler(arguments.getApplicationUsage()));
|
||||
|
||||
// add the record camera path handler
|
||||
viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);
|
||||
|
||||
// add the LOD Scale handler
|
||||
viewer.addEventHandler(new osgViewer::LODScaleHandler);
|
||||
|
||||
// add the screen capture handler
|
||||
viewer.addEventHandler(new osgViewer::ScreenCaptureHandler);
|
||||
|
||||
// Register shader generator callback
|
||||
ShaderGenReadFileCallback *readFileCallback = new ShaderGenReadFileCallback;
|
||||
// All read nodes will inherit root state set.
|
||||
readFileCallback->setRootStateSet(viewer.getCamera()->getStateSet());
|
||||
osgDB::Registry::instance()->setReadFileCallback(readFileCallback);
|
||||
|
||||
// load the data
|
||||
osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
|
||||
if (!loadedModel)
|
||||
{
|
||||
std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// any option left unread are converted into errors to write out later.
|
||||
arguments.reportRemainingOptionsAsUnrecognized();
|
||||
|
||||
// report any errors if they have occurred when parsing the program arguments.
|
||||
if (arguments.errors())
|
||||
{
|
||||
arguments.writeErrorMessages(std::cout);
|
||||
return 1;
|
||||
}
|
||||
|
||||
viewer.setSceneData( loadedModel.get() );
|
||||
|
||||
viewer.realize();
|
||||
|
||||
return viewer.run();
|
||||
|
||||
}
|
84
include/osgUtil/ShaderGen
Normal file
84
include/osgUtil/ShaderGen
Normal file
@ -0,0 +1,84 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2009 Robert Osfield
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Shader generator framework.
|
||||
* \author Maciej Krol
|
||||
*/
|
||||
|
||||
#ifndef OSGUTIL_SHADER_STATE_
|
||||
#define OSGUTIL_SHADER_STATE_ 1
|
||||
|
||||
#include <osgUtil/Export>
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osg/State>
|
||||
|
||||
namespace osgUtil
|
||||
{
|
||||
|
||||
class OSGUTIL_EXPORT ShaderGenCache : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
enum StateMask
|
||||
{
|
||||
BLEND = 1,
|
||||
LIGHTING = 2,
|
||||
FOG = 4,
|
||||
DIFFUSE_MAP = 8, //< Texture in unit 0
|
||||
NORMAL_MAP = 16 //< Texture in unit 1 and vertex attribute array 6
|
||||
};
|
||||
|
||||
typedef std::map<unsigned int, osg::ref_ptr<osg::StateSet> > StateSetMap;
|
||||
|
||||
ShaderGenCache() {};
|
||||
|
||||
void setStateSet(unsigned int stateMask, osg::StateSet *program);
|
||||
osg::StateSet *getStateSet(unsigned int stateMask) const;
|
||||
osg::StateSet *getOrCreateStateSet(unsigned int stateMask);
|
||||
|
||||
protected:
|
||||
osg::StateSet *createStateSet(unsigned int stateMask) const;
|
||||
mutable OpenThreads::Mutex _mutex;
|
||||
StateSetMap _stateSetMap;
|
||||
|
||||
};
|
||||
|
||||
class OSGUTIL_EXPORT ShaderGenVisitor : public osg::NodeVisitor
|
||||
{
|
||||
public:
|
||||
ShaderGenVisitor();
|
||||
ShaderGenVisitor(ShaderGenCache *stateCache);
|
||||
|
||||
void setStateCache(ShaderGenCache *stateCache) { _stateCache = stateCache; }
|
||||
ShaderGenCache *getStateCache() const { return _stateCache.get(); }
|
||||
|
||||
/// Top level state set applied as the first one.
|
||||
void setRootStateSet(osg::StateSet *stateSet);
|
||||
osg::StateSet *getRootStateSet() const { return _rootStateSet.get(); }
|
||||
|
||||
void apply(osg::Node &node);
|
||||
void apply(osg::Geode &geode);
|
||||
|
||||
void reset();
|
||||
|
||||
protected:
|
||||
void update(osg::Drawable *drawable);
|
||||
|
||||
osg::ref_ptr<ShaderGenCache> _stateCache;
|
||||
osg::ref_ptr<osg::State> _state;
|
||||
osg::ref_ptr<osg::StateSet> _rootStateSet;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -37,6 +37,7 @@ SET(LIB_PUBLIC_HEADERS
|
||||
${HEADER_PATH}/ReversePrimitiveFunctor
|
||||
${HEADER_PATH}/SceneView
|
||||
${HEADER_PATH}/SceneGraphBuilder
|
||||
${HEADER_PATH}/ShaderGen
|
||||
${HEADER_PATH}/Simplifier
|
||||
${HEADER_PATH}/SmoothingVisitor
|
||||
${HEADER_PATH}/StateGraph
|
||||
@ -76,6 +77,7 @@ ADD_LIBRARY(${LIB_NAME}
|
||||
RenderStage.cpp
|
||||
ReversePrimitiveFunctor.cpp
|
||||
SceneView.cpp
|
||||
ShaderGen.cpp
|
||||
Simplifier.cpp
|
||||
SmoothingVisitor.cpp
|
||||
SceneGraphBuilder.cpp
|
||||
|
383
src/osgUtil/ShaderGen.cpp
Normal file
383
src/osgUtil/ShaderGen.cpp
Normal file
@ -0,0 +1,383 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2009 Robert Osfield
|
||||
*
|
||||
* This library is open source and may be redistributed and/or modified under
|
||||
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
||||
* (at your option) any later version. The full license is in LICENSE file
|
||||
* included with this distribution, and on the openscenegraph.org website.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Shader generator framework.
|
||||
* \author Maciej Krol
|
||||
*/
|
||||
|
||||
#include <osgUtil/ShaderGen>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry> // for ShaderGenVisitor::update
|
||||
#include <sstream>
|
||||
|
||||
using namespace osgUtil;
|
||||
|
||||
namespace osgUtil
|
||||
{
|
||||
|
||||
/// State extended by mode/attribute accessors
|
||||
class StateEx : public osg::State
|
||||
{
|
||||
public:
|
||||
StateEx() : State() {}
|
||||
|
||||
osg::StateAttribute::GLModeValue getMode(osg::StateAttribute::GLMode mode,
|
||||
osg::StateAttribute::GLModeValue def = osg::StateAttribute::INHERIT) const
|
||||
{
|
||||
return getMode(_modeMap, mode, def);
|
||||
}
|
||||
|
||||
osg::StateAttribute *getAttribute(osg::StateAttribute::Type type, unsigned int member = 0) const
|
||||
{
|
||||
return getAttribute(_attributeMap, type, member);
|
||||
}
|
||||
|
||||
osg::StateAttribute::GLModeValue getTextureMode(unsigned int unit,
|
||||
osg::StateAttribute::GLMode mode,
|
||||
osg::StateAttribute::GLModeValue def = osg::StateAttribute::INHERIT) const
|
||||
{
|
||||
return unit < _textureModeMapList.size() ? getMode(_textureModeMapList[unit], mode, def) : def;
|
||||
}
|
||||
|
||||
osg::StateAttribute *getTextureAttribute(unsigned int unit, osg::StateAttribute::Type type) const
|
||||
{
|
||||
return unit < _textureAttributeMapList.size() ? getAttribute(_textureAttributeMapList[unit], type, 0) : 0;
|
||||
}
|
||||
|
||||
osg::Uniform *getUniform(const std::string& name) const
|
||||
{
|
||||
UniformMap::const_iterator it = _uniformMap.find(name);
|
||||
return it != _uniformMap.end() ?
|
||||
const_cast<osg::Uniform *>(it->second.uniformVec.back().first) : 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
osg::StateAttribute::GLModeValue getMode(const ModeMap &modeMap,
|
||||
osg::StateAttribute::GLMode mode,
|
||||
osg::StateAttribute::GLModeValue def = osg::StateAttribute::INHERIT) const
|
||||
{
|
||||
ModeMap::const_iterator it = modeMap.find(mode);
|
||||
return (it != modeMap.end() && it->second.valueVec.size()) ? it->second.valueVec.back() : def;
|
||||
}
|
||||
|
||||
osg::StateAttribute *getAttribute(const AttributeMap &attributeMap,
|
||||
osg::StateAttribute::Type type, unsigned int member = 0) const
|
||||
{
|
||||
AttributeMap::const_iterator it = attributeMap.find(std::make_pair(type, member));
|
||||
return (it != attributeMap.end() && it->second.attributeVec.size()) ?
|
||||
const_cast<osg::StateAttribute*>(it->second.attributeVec.back().first) : 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void ShaderGenCache::setStateSet(unsigned int stateMask, osg::StateSet *stateSet)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
_stateSetMap[stateMask] = stateSet;
|
||||
}
|
||||
|
||||
osg::StateSet *ShaderGenCache::getStateSet(unsigned int stateMask) const
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
StateSetMap::const_iterator it = _stateSetMap.find(stateMask);
|
||||
return (it != _stateSetMap.end()) ? it->second.get() : 0;
|
||||
}
|
||||
|
||||
osg::StateSet *ShaderGenCache::getOrCreateStateSet(unsigned int stateMask)
|
||||
{
|
||||
OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
|
||||
StateSetMap::iterator it = _stateSetMap.find(stateMask);
|
||||
if (it == _stateSetMap.end())
|
||||
{
|
||||
osg::StateSet *stateSet = createStateSet(stateMask);
|
||||
_stateSetMap.insert(it, std::make_pair(stateMask, stateSet));
|
||||
return stateSet;
|
||||
}
|
||||
return it->second.get();
|
||||
}
|
||||
|
||||
osg::StateSet *ShaderGenCache::createStateSet(unsigned int stateMask) const
|
||||
{
|
||||
osg::StateSet *stateSet = new osg::StateSet;
|
||||
osg::Program *program = new osg::Program;
|
||||
stateSet->setAttribute(program);
|
||||
|
||||
std::ostringstream vert;
|
||||
std::ostringstream frag;
|
||||
|
||||
// write varyings
|
||||
if ((stateMask & LIGHTING) && !(stateMask & NORMAL_MAP))
|
||||
{
|
||||
vert << "varying vec3 normalDir;\n";
|
||||
}
|
||||
|
||||
if (stateMask & (LIGHTING | NORMAL_MAP))
|
||||
{
|
||||
vert << "varying vec3 lightDir;\n";
|
||||
}
|
||||
|
||||
if (stateMask & (LIGHTING | NORMAL_MAP | FOG))
|
||||
{
|
||||
vert << "varying vec3 viewDir;\n";
|
||||
}
|
||||
|
||||
// copy varying to fragment shader
|
||||
frag << vert.str();
|
||||
|
||||
// write uniforms and attributes
|
||||
int unit = 0;
|
||||
if (stateMask & DIFFUSE_MAP)
|
||||
{
|
||||
osg::Uniform *diffuseMap = new osg::Uniform("diffuseMap", unit++);
|
||||
stateSet->addUniform(diffuseMap);
|
||||
frag << "uniform sampler2D diffuseMap;\n";
|
||||
}
|
||||
|
||||
if (stateMask & NORMAL_MAP)
|
||||
{
|
||||
osg::Uniform *normalMap = new osg::Uniform("normalMap", unit++);
|
||||
stateSet->addUniform(normalMap);
|
||||
frag << "uniform sampler2D normalMap;\n";
|
||||
program->addBindAttribLocation("tangent", 6);
|
||||
vert << "attribute vec3 tangent;\n";
|
||||
}
|
||||
|
||||
vert << "\n"\
|
||||
"void main()\n"\
|
||||
"{\n"\
|
||||
" gl_Position = ftransform();\n";
|
||||
|
||||
if (stateMask & (DIFFUSE_MAP | NORMAL_MAP))
|
||||
{
|
||||
vert << " gl_TexCoord[0] = gl_MultiTexCoord0;\n";
|
||||
}
|
||||
|
||||
if (stateMask & NORMAL_MAP)
|
||||
{
|
||||
vert <<
|
||||
" vec3 n = gl_NormalMatrix * gl_Normal;\n"\
|
||||
" vec3 t = gl_NormalMatrix * tangent;\n"\
|
||||
" vec3 b = cross(n, t);\n"\
|
||||
" vec3 dir = -vec3(gl_ModelViewMatrix * gl_Vertex);\n"\
|
||||
" viewDir.x = dot(dir, t);\n"\
|
||||
" viewDir.y = dot(dir, b);\n"\
|
||||
" viewDir.z = dot(dir, n);\n"\
|
||||
" vec4 lpos = gl_LightSource[0].position;\n"\
|
||||
" if (lpos.w == 0.0)\n"\
|
||||
" dir = lpos.xyz;\n"\
|
||||
" else\n"\
|
||||
" dir += lpos.xyz;\n"\
|
||||
" lightDir.x = dot(dir, t);\n"\
|
||||
" lightDir.y = dot(dir, b);\n"\
|
||||
" lightDir.z = dot(dir, n);\n";
|
||||
}
|
||||
else if (stateMask & LIGHTING)
|
||||
{
|
||||
vert <<
|
||||
" normalDir = gl_NormalMatrix * gl_Normal;\n"\
|
||||
" vec3 dir = -vec3(gl_ModelViewMatrix * gl_Vertex);\n"\
|
||||
" viewDir = dir;\n"\
|
||||
" vec4 lpos = gl_LightSource[0].position;\n"\
|
||||
" if (lpos.w == 0.0)\n"\
|
||||
" lightDir = lpos.xyz;\n"\
|
||||
" else\n"\
|
||||
" lightDir = lpos.xyz + dir;\n";
|
||||
}
|
||||
else if (stateMask & FOG)
|
||||
{
|
||||
vert <<
|
||||
" viewDir = -vec3(gl_ModelViewMatrix * gl_Vertex);\n"\
|
||||
" gl_FrontColor = gl_Color;\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
vert << " gl_FrontColor = gl_Color;\n";
|
||||
}
|
||||
|
||||
vert << "}\n";
|
||||
|
||||
frag << "\n"\
|
||||
"void main()\n"\
|
||||
"{\n";
|
||||
|
||||
if (stateMask & DIFFUSE_MAP)
|
||||
{
|
||||
frag << " vec4 base = texture2D(diffuseMap, gl_TexCoord[0].st);\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
frag << " vec4 base = vec4(1.0);\n";
|
||||
}
|
||||
|
||||
if (stateMask & NORMAL_MAP)
|
||||
{
|
||||
frag << " vec3 normalDir = texture2D(normalMap, gl_TexCoord[0].st).xyz*2.0-1.0;\n";
|
||||
}
|
||||
|
||||
if (stateMask & (LIGHTING | NORMAL_MAP))
|
||||
{
|
||||
frag <<
|
||||
" vec3 nd = normalize(normalDir);\n"\
|
||||
" vec3 ld = normalize(lightDir);\n"\
|
||||
" vec3 vd = normalize(viewDir);\n"\
|
||||
" vec4 color = gl_FrontLightModelProduct.sceneColor;\n"\
|
||||
" color += gl_FrontLightProduct[0].ambient;\n"\
|
||||
" float diff = max(dot(ld, nd), 0.0);\n"\
|
||||
" color += gl_FrontLightProduct[0].diffuse * diff;\n"\
|
||||
" color *= base;\n"\
|
||||
" if (diff > 0.0)\n"\
|
||||
" {\n"\
|
||||
" vec3 halfDir = normalize(ld+vd);\n"\
|
||||
" color.rgb += base.a * gl_FrontLightProduct[0].specular.rgb * \n"\
|
||||
" pow(max(dot(halfDir, nd), 0.0), gl_FrontMaterial.shininess);\n"\
|
||||
" }\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
frag << " vec4 color = base;\n";
|
||||
}
|
||||
|
||||
if (!(stateMask & LIGHTING))
|
||||
{
|
||||
frag << " color *= gl_Color;\n";
|
||||
}
|
||||
|
||||
if (stateMask & FOG)
|
||||
{
|
||||
frag <<
|
||||
" float d2 = dot(viewDir, viewDir);//gl_FragCoord.z/gl_FragCoord.w;\n"\
|
||||
" float f = exp2(-1.442695*gl_Fog.density*gl_Fog.density*d2);\n"\
|
||||
" color.rgb = mix(gl_Fog.color.rgb, color.rgb, clamp(f, 0.0, 1.0));\n";
|
||||
}
|
||||
|
||||
frag << " gl_FragColor = color;\n";
|
||||
frag << "}\n";
|
||||
|
||||
std::string vertstr = vert.str();
|
||||
std::string fragstr = frag.str();
|
||||
|
||||
osg::notify(osg::DEBUG_INFO) << "ShaderGenCache Vertex shader:\n" << vertstr << std::endl;
|
||||
osg::notify(osg::DEBUG_INFO) << "ShaderGenCache Fragment shader:\n" << fragstr << std::endl;
|
||||
|
||||
program->addShader(new osg::Shader(osg::Shader::VERTEX, vertstr));
|
||||
program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragstr));
|
||||
|
||||
return stateSet;
|
||||
}
|
||||
|
||||
ShaderGenVisitor::ShaderGenVisitor() :
|
||||
NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
_stateCache(new ShaderGenCache),
|
||||
_state(new StateEx)
|
||||
{
|
||||
}
|
||||
|
||||
ShaderGenVisitor::ShaderGenVisitor(ShaderGenCache *stateCache) :
|
||||
NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
_stateCache(stateCache),
|
||||
_state(new StateEx)
|
||||
{
|
||||
}
|
||||
|
||||
void ShaderGenVisitor::setRootStateSet(osg::StateSet *stateSet)
|
||||
{
|
||||
if (_rootStateSet.valid())
|
||||
_state->removeStateSet(0);
|
||||
_rootStateSet = stateSet;
|
||||
if (_rootStateSet.valid())
|
||||
_state->pushStateSet(_rootStateSet.get());
|
||||
}
|
||||
|
||||
void ShaderGenVisitor::reset()
|
||||
{
|
||||
_state->popAllStateSets();
|
||||
if (_rootStateSet.valid())
|
||||
_state->pushStateSet(_rootStateSet.get());
|
||||
}
|
||||
|
||||
void ShaderGenVisitor::apply(osg::Node &node)
|
||||
{
|
||||
osg::StateSet *stateSet = node.getStateSet();
|
||||
|
||||
if (stateSet)
|
||||
_state->pushStateSet(stateSet);
|
||||
|
||||
traverse(node);
|
||||
|
||||
if (stateSet)
|
||||
_state->popStateSet();
|
||||
}
|
||||
|
||||
void ShaderGenVisitor::apply(osg::Geode &geode)
|
||||
{
|
||||
osg::StateSet *stateSet = geode.getStateSet();
|
||||
if (stateSet)
|
||||
_state->pushStateSet(stateSet);
|
||||
|
||||
for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
|
||||
{
|
||||
osg::Drawable *drawable = geode.getDrawable(i);
|
||||
osg::StateSet *ss = drawable->getStateSet();
|
||||
if (ss)
|
||||
_state->pushStateSet(ss);
|
||||
|
||||
update(drawable);
|
||||
|
||||
if (ss)
|
||||
_state->popStateSet();
|
||||
}
|
||||
|
||||
if (stateSet)
|
||||
_state->popStateSet();
|
||||
}
|
||||
|
||||
void ShaderGenVisitor::update(osg::Drawable *drawable)
|
||||
{
|
||||
// update only geometry due to compatibility issues with user defined drawables
|
||||
osg::Geometry *geometry = drawable->asGeometry();
|
||||
if (!geometry)
|
||||
return;
|
||||
|
||||
StateEx *state = static_cast<StateEx *>(_state.get());
|
||||
// skip nodes without state sets
|
||||
if (state->getStateSetStackSize() == (_rootStateSet.valid() ? 1 : 0))
|
||||
return;
|
||||
|
||||
// skip state sets with already attached programs
|
||||
if (state->getAttribute(osg::StateAttribute::PROGRAM))
|
||||
return;
|
||||
|
||||
unsigned int stateMask = 0;
|
||||
//if (state->getMode(GL_BLEND) & osg::StateAttribute::ON)
|
||||
// stateMask |= ShaderGen::BLEND;
|
||||
if (state->getMode(GL_LIGHTING) & osg::StateAttribute::ON)
|
||||
stateMask |= ShaderGenCache::LIGHTING;
|
||||
if (state->getMode(GL_FOG) & osg::StateAttribute::ON)
|
||||
stateMask |= ShaderGenCache::FOG;
|
||||
if (state->getTextureAttribute(0, osg::StateAttribute::TEXTURE))
|
||||
stateMask |= ShaderGenCache::DIFFUSE_MAP;
|
||||
if (state->getTextureAttribute(1, osg::StateAttribute::TEXTURE) &&
|
||||
geometry->getVertexAttribArray(6)) //tangent
|
||||
stateMask |= ShaderGenCache::NORMAL_MAP;
|
||||
|
||||
// Get program and uniforms for accumulated state.
|
||||
osg::StateSet *progss = _stateCache->getOrCreateStateSet(stateMask);
|
||||
// Set program and uniforms to the last state set.
|
||||
osg::StateSet *ss = const_cast<osg::StateSet *>(state->getStateSetStack().back());
|
||||
ss->setAttribute(progss->getAttribute(osg::StateAttribute::PROGRAM));
|
||||
ss->setUniformList(progss->getUniformList());
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user