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

Revision 11164, 12.3 kB (checked in by robert, 4 years ago)

Replaced use of unsigned int/enum mask combinations with int/enum mask combinations to avoid the need for casting enums to unsigned ints,
and to avoid associated warnings.

Update wrappers to reflect these changes.

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