root/OpenSceneGraph/trunk/src/osgUtil/ShaderGen.cpp @ 10078

Revision 10078, 11.8 kB (checked in by robert, 5 years ago)

Warning fix

Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2009 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14/**
15 * \brief    Shader generator framework.
16 * \author   Maciej Krol
17 */
18
19#include <osgUtil/ShaderGen>
20#include <osg/Geode>
21#include <osg/Geometry> // for ShaderGenVisitor::update
22#include <sstream>
23
24using namespace osgUtil;
25
26namespace osgUtil
27{
28
29/// State extended by mode/attribute accessors
30class StateEx : public osg::State
31{
32public:
33    StateEx() : State() {}
34
35    osg::StateAttribute::GLModeValue getMode(osg::StateAttribute::GLMode mode,
36        osg::StateAttribute::GLModeValue def = osg::StateAttribute::INHERIT) const
37    {
38        return getMode(_modeMap, mode, def);
39    }
40
41    osg::StateAttribute *getAttribute(osg::StateAttribute::Type type, unsigned int member = 0) const
42    {
43        return getAttribute(_attributeMap, type, member);
44    }
45
46    osg::StateAttribute::GLModeValue getTextureMode(unsigned int unit,
47        osg::StateAttribute::GLMode mode,
48        osg::StateAttribute::GLModeValue def = osg::StateAttribute::INHERIT) const
49    {
50        return unit < _textureModeMapList.size() ? getMode(_textureModeMapList[unit], mode, def) : def;
51    }
52
53    osg::StateAttribute *getTextureAttribute(unsigned int unit, osg::StateAttribute::Type type) const
54    {
55        return unit < _textureAttributeMapList.size() ? getAttribute(_textureAttributeMapList[unit], type, 0) : 0;
56    }
57
58    osg::Uniform *getUniform(const std::string& name) const
59    {
60        UniformMap::const_iterator it = _uniformMap.find(name);
61        return it != _uniformMap.end() ?
62            const_cast<osg::Uniform *>(it->second.uniformVec.back().first) : 0;
63    }
64
65protected:
66
67    osg::StateAttribute::GLModeValue getMode(const ModeMap &modeMap,
68        osg::StateAttribute::GLMode mode,
69        osg::StateAttribute::GLModeValue def = osg::StateAttribute::INHERIT) const
70    {
71        ModeMap::const_iterator it = modeMap.find(mode);
72        return (it != modeMap.end() && it->second.valueVec.size()) ? it->second.valueVec.back() : def;
73    }
74
75    osg::StateAttribute *getAttribute(const AttributeMap &attributeMap,
76        osg::StateAttribute::Type type, unsigned int member = 0) const
77    {
78        AttributeMap::const_iterator it = attributeMap.find(std::make_pair(type, member));
79        return (it != attributeMap.end() && it->second.attributeVec.size()) ?
80            const_cast<osg::StateAttribute*>(it->second.attributeVec.back().first) : 0;
81    }
82};
83
84}
85
86void ShaderGenCache::setStateSet(unsigned int stateMask, osg::StateSet *stateSet)
87{
88    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
89    _stateSetMap[stateMask] = stateSet;
90}
91
92osg::StateSet *ShaderGenCache::getStateSet(unsigned int stateMask) const
93{
94    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
95    StateSetMap::const_iterator it = _stateSetMap.find(stateMask);
96    return (it != _stateSetMap.end()) ? it->second.get() : 0;
97}
98
99osg::StateSet *ShaderGenCache::getOrCreateStateSet(unsigned int stateMask)
100{
101    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
102    StateSetMap::iterator it = _stateSetMap.find(stateMask);
103    if (it == _stateSetMap.end())
104    {
105        osg::StateSet *stateSet = createStateSet(stateMask);
106        _stateSetMap.insert(it, std::make_pair(stateMask, stateSet));
107        return stateSet;
108    }
109    return it->second.get();
110}
111
112osg::StateSet *ShaderGenCache::createStateSet(unsigned int stateMask) const
113{
114    osg::StateSet *stateSet = new osg::StateSet;
115    osg::Program *program = new osg::Program;
116    stateSet->setAttribute(program);
117
118    std::ostringstream vert;
119    std::ostringstream frag;
120
121    // write varyings
122    if ((stateMask & LIGHTING) && !(stateMask & NORMAL_MAP))
123    {
124        vert << "varying vec3 normalDir;\n";
125    }
126
127    if (stateMask & (LIGHTING | NORMAL_MAP))
128    {
129        vert << "varying vec3 lightDir;\n";
130    }
131
132    if (stateMask & (LIGHTING | NORMAL_MAP | FOG))
133    {
134        vert << "varying vec3 viewDir;\n";
135    }
136   
137    // copy varying to fragment shader
138    frag << vert.str();
139
140    // write uniforms and attributes
141    int unit = 0;
142    if (stateMask & DIFFUSE_MAP)
143    {
144        osg::Uniform *diffuseMap = new osg::Uniform("diffuseMap", unit++);
145        stateSet->addUniform(diffuseMap);
146        frag << "uniform sampler2D diffuseMap;\n";
147    }
148
149    if (stateMask & NORMAL_MAP)
150    {
151        osg::Uniform *normalMap = new osg::Uniform("normalMap", unit++);
152        stateSet->addUniform(normalMap);
153        frag << "uniform sampler2D normalMap;\n";
154        program->addBindAttribLocation("tangent", 6);
155        vert << "attribute vec3 tangent;\n";
156    }
157
158    vert << "\n"\
159        "void main()\n"\
160        "{\n"\
161        "  gl_Position = ftransform();\n";
162
163    if (stateMask & (DIFFUSE_MAP | NORMAL_MAP))
164    {
165        vert << "  gl_TexCoord[0] = gl_MultiTexCoord0;\n";
166    }
167
168    if (stateMask & NORMAL_MAP)
169    {
170        vert <<
171            "  vec3 n = gl_NormalMatrix * gl_Normal;\n"\
172            "  vec3 t = gl_NormalMatrix * tangent;\n"\
173            "  vec3 b = cross(n, t);\n"\
174            "  vec3 dir = -vec3(gl_ModelViewMatrix * gl_Vertex);\n"\
175            "  viewDir.x = dot(dir, t);\n"\
176            "  viewDir.y = dot(dir, b);\n"\
177            "  viewDir.z = dot(dir, n);\n"\
178            "  vec4 lpos = gl_LightSource[0].position;\n"\
179            "  if (lpos.w == 0.0)\n"\
180            "    dir = lpos.xyz;\n"\
181            "  else\n"\
182            "    dir += lpos.xyz;\n"\
183            "  lightDir.x = dot(dir, t);\n"\
184            "  lightDir.y = dot(dir, b);\n"\
185            "  lightDir.z = dot(dir, n);\n";
186    }
187    else if (stateMask & LIGHTING)
188    {
189        vert <<
190            "  normalDir = gl_NormalMatrix * gl_Normal;\n"\
191            "  vec3 dir = -vec3(gl_ModelViewMatrix * gl_Vertex);\n"\
192            "  viewDir = dir;\n"\
193            "  vec4 lpos = gl_LightSource[0].position;\n"\
194            "  if (lpos.w == 0.0)\n"\
195            "    lightDir = lpos.xyz;\n"\
196            "  else\n"\
197            "    lightDir = lpos.xyz + dir;\n";
198    }
199    else if (stateMask & FOG)
200    {
201        vert <<
202            "  viewDir = -vec3(gl_ModelViewMatrix * gl_Vertex);\n"\
203            "  gl_FrontColor = gl_Color;\n";
204    }
205    else
206    {
207        vert << "  gl_FrontColor = gl_Color;\n";
208    }
209   
210    vert << "}\n";
211
212    frag << "\n"\
213        "void main()\n"\
214        "{\n";
215
216    if (stateMask & DIFFUSE_MAP)
217    {
218        frag << "  vec4 base = texture2D(diffuseMap, gl_TexCoord[0].st);\n";
219    }
220    else
221    {
222        frag << "  vec4 base = vec4(1.0);\n";
223    }
224
225    if (stateMask & NORMAL_MAP)
226    {
227        frag << "  vec3 normalDir = texture2D(normalMap, gl_TexCoord[0].st).xyz*2.0-1.0;\n";
228    }
229
230    if (stateMask & (LIGHTING | NORMAL_MAP))
231    {
232        frag <<
233            "  vec3 nd = normalize(normalDir);\n"\
234            "  vec3 ld = normalize(lightDir);\n"\
235            "  vec3 vd = normalize(viewDir);\n"\
236            "  vec4 color = gl_FrontLightModelProduct.sceneColor;\n"\
237            "  color += gl_FrontLightProduct[0].ambient;\n"\
238            "  float diff = max(dot(ld, nd), 0.0);\n"\
239            "  color += gl_FrontLightProduct[0].diffuse * diff;\n"\
240            "  color *= base;\n"\
241            "  if (diff > 0.0)\n"\
242            "  {\n"\
243            "    vec3 halfDir = normalize(ld+vd);\n"\
244            "    color.rgb += base.a * gl_FrontLightProduct[0].specular.rgb * \n"\
245            "      pow(max(dot(halfDir, nd), 0.0), gl_FrontMaterial.shininess);\n"\
246            "  }\n";
247    }
248    else
249    {
250        frag << "  vec4 color = base;\n";
251    }
252
253    if (!(stateMask & LIGHTING))
254    {
255        frag << "  color *= gl_Color;\n";
256    }
257
258    if (stateMask & FOG)
259    {
260        frag <<
261            "  float d2 = dot(viewDir, viewDir);//gl_FragCoord.z/gl_FragCoord.w;\n"\
262            "  float f = exp2(-1.442695*gl_Fog.density*gl_Fog.density*d2);\n"\
263            "  color.rgb = mix(gl_Fog.color.rgb, color.rgb, clamp(f, 0.0, 1.0));\n";
264    }
265   
266    frag << "  gl_FragColor = color;\n";
267    frag << "}\n";
268
269    std::string vertstr = vert.str();
270    std::string fragstr = frag.str();
271
272    osg::notify(osg::DEBUG_INFO) << "ShaderGenCache Vertex shader:\n" << vertstr << std::endl;
273    osg::notify(osg::DEBUG_INFO) << "ShaderGenCache Fragment shader:\n" << fragstr << std::endl;
274
275    program->addShader(new osg::Shader(osg::Shader::VERTEX, vertstr));
276    program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragstr));
277
278    return stateSet;
279}
280
281ShaderGenVisitor::ShaderGenVisitor() :
282    NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
283    _stateCache(new ShaderGenCache),
284    _state(new StateEx)
285{
286}
287
288ShaderGenVisitor::ShaderGenVisitor(ShaderGenCache *stateCache) :
289    NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
290    _stateCache(stateCache),
291    _state(new StateEx)
292{
293}
294
295void ShaderGenVisitor::setRootStateSet(osg::StateSet *stateSet)
296{
297    if (_rootStateSet.valid())
298        _state->removeStateSet(0);
299    _rootStateSet = stateSet;
300    if (_rootStateSet.valid())
301        _state->pushStateSet(_rootStateSet.get());
302}
303
304void ShaderGenVisitor::reset()
305{
306    _state->popAllStateSets();
307    if (_rootStateSet.valid())
308        _state->pushStateSet(_rootStateSet.get());
309}
310
311void ShaderGenVisitor::apply(osg::Node &node)
312{
313    osg::StateSet *stateSet = node.getStateSet();
314
315    if (stateSet)
316        _state->pushStateSet(stateSet);
317
318    traverse(node);
319
320    if (stateSet)
321        _state->popStateSet();
322}
323
324void ShaderGenVisitor::apply(osg::Geode &geode)
325{
326    osg::StateSet *stateSet = geode.getStateSet();
327    if (stateSet)
328        _state->pushStateSet(stateSet);
329
330    for (unsigned int i=0; i<geode.getNumDrawables(); ++i)
331    {
332        osg::Drawable *drawable = geode.getDrawable(i);
333        osg::StateSet *ss = drawable->getStateSet();
334        if (ss)
335            _state->pushStateSet(ss);
336
337        update(drawable);
338
339        if (ss)
340            _state->popStateSet();
341    }
342
343    if (stateSet)
344        _state->popStateSet();
345}
346
347void ShaderGenVisitor::update(osg::Drawable *drawable)
348{
349    // update only geometry due to compatibility issues with user defined drawables
350    osg::Geometry *geometry = drawable->asGeometry();
351    if (!geometry)
352        return;
353
354    StateEx *state = static_cast<StateEx *>(_state.get());
355    // skip nodes without state sets
356    if (state->getStateSetStackSize() == (_rootStateSet.valid() ? 1u : 0u))
357        return;
358
359    // skip state sets with already attached programs
360    if (state->getAttribute(osg::StateAttribute::PROGRAM))
361        return;
362
363    unsigned int stateMask = 0;
364    //if (state->getMode(GL_BLEND) & osg::StateAttribute::ON)
365    //    stateMask |= ShaderGen::BLEND;
366    if (state->getMode(GL_LIGHTING) & osg::StateAttribute::ON)
367        stateMask |= ShaderGenCache::LIGHTING;
368    if (state->getMode(GL_FOG) & osg::StateAttribute::ON)
369        stateMask |= ShaderGenCache::FOG;
370    if (state->getTextureAttribute(0, osg::StateAttribute::TEXTURE))
371        stateMask |= ShaderGenCache::DIFFUSE_MAP;
372    if (state->getTextureAttribute(1, osg::StateAttribute::TEXTURE) &&
373        geometry->getVertexAttribArray(6)) //tangent
374        stateMask |= ShaderGenCache::NORMAL_MAP;
375
376    // Get program and uniforms for accumulated state.
377    osg::StateSet *progss = _stateCache->getOrCreateStateSet(stateMask);
378    // Set program and uniforms to the last state set.
379    osg::StateSet *ss = const_cast<osg::StateSet *>(state->getStateSetStack().back());
380    ss->setAttribute(progss->getAttribute(osg::StateAttribute::PROGRAM));
381    ss->setUniformList(progss->getUniformList());
382   
383}
Note: See TracBrowser for help on using the browser.