root/OpenSceneGraph/trunk/src/osgFX/BumpMapping.cpp @ 13041

Revision 13041, 25.5 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osgFX/BumpMapping>
2#include <osgFX/Registry>
3
4#include <osg/VertexProgram>
5#include <osg/FragmentProgram>
6#include <osg/Texture2D>
7#include <osg/Depth>
8#include <osg/TexEnv>
9#include <osg/TexEnvCombine>
10#include <osg/BlendFunc>
11#include <osg/Geometry>
12#include <osg/Notify>
13
14#include <osgUtil/TangentSpaceGenerator>
15
16#include <osgDB/ReadFile>
17
18#include <sstream>
19
20using namespace osgFX;
21
22namespace
23{
24
25    using osg::NodeVisitor;
26
27     // this is a visitor class that prepares all geometries in a subgraph
28    // by calling prepareGeometry() which in turn generates tangent-space
29    // basis vectors
30    class TsgVisitor: public NodeVisitor {
31    public:
32        TsgVisitor(BumpMapping* bm): NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN), _bm(bm) {}
33
34        META_NodeVisitor("osgFX","TsgVisitor")
35
36        void apply(osg::Geode& geode)
37        {
38            for (unsigned i=0; i<geode.getNumDrawables(); ++i) {
39                osg::Geometry* geo = dynamic_cast<osg::Geometry* >(geode.getDrawable(i));
40                if (geo) {
41                    _bm->prepareGeometry(geo);
42                }
43            }
44            NodeVisitor::apply(geode);
45        }
46    private:
47        BumpMapping* _bm;
48    };
49
50
51    // this visitor generates texture coordinates for all geometries in a
52    // subgraph. It is used only for demo purposes.
53    class TexCoordGenerator: public osg::NodeVisitor {
54    public:
55        TexCoordGenerator(int du, int nu): NodeVisitor(NodeVisitor::TRAVERSE_ALL_CHILDREN), du_(du), nu_(nu) {}
56
57        META_NodeVisitor("osgFX","TexCoordGenerator")
58
59        void apply(osg::Geode& geode)
60        {
61            const osg::BoundingSphere &bsphere = geode.getBound();
62            float scale = 10;
63            if (bsphere.radius() != 0) {
64                scale = 5 / bsphere.radius();
65            }
66            for (unsigned i=0; i<geode.getNumDrawables(); ++i) {
67                osg::Geometry* geo = dynamic_cast<osg::Geometry* >(geode.getDrawable(i));
68                if (geo) {
69                    osg::ref_ptr<osg::Vec2Array> tc = generate_coords(geo->getVertexArray(), geo->getNormalArray(), scale);
70                    geo->setTexCoordArray(du_, tc.get());
71                    geo->setTexCoordArray(nu_, tc.get());
72                }
73            }
74            NodeVisitor::apply(geode);
75        }
76
77    protected:
78        osg::Vec2Array* generate_coords(osg::Array* vx, osg::Array* nx, float scale)
79        {
80            osg::Vec2Array* v2a = dynamic_cast<osg::Vec2Array*>(vx);
81            osg::Vec3Array* v3a = dynamic_cast<osg::Vec3Array*>(vx);
82            osg::Vec4Array* v4a = dynamic_cast<osg::Vec4Array*>(vx);
83            osg::Vec2Array* n2a = dynamic_cast<osg::Vec2Array*>(nx);
84            osg::Vec3Array* n3a = dynamic_cast<osg::Vec3Array*>(nx);
85            osg::Vec4Array* n4a = dynamic_cast<osg::Vec4Array*>(nx);
86
87            osg::ref_ptr<osg::Vec2Array> tc = new osg::Vec2Array;
88            for (unsigned i=0; i<vx->getNumElements(); ++i) {
89
90                osg::Vec3 P;
91                if (v2a) P.set((*v2a)[i].x(), (*v2a)[i].y(), 0);
92                if (v3a) P.set((*v3a)[i].x(), (*v3a)[i].y(), (*v3a)[i].z());
93                if (v4a) P.set((*v4a)[i].x(), (*v4a)[i].y(), (*v4a)[i].z());
94
95                osg::Vec3 N(0, 0, 1);
96                if (n2a) N.set((*n2a)[i].x(), (*n2a)[i].y(), 0);
97                if (n3a) N.set((*n3a)[i].x(), (*n3a)[i].y(), (*n3a)[i].z());
98                if (n4a) N.set((*n4a)[i].x(), (*n4a)[i].y(), (*n4a)[i].z());
99
100                int axis = 0;
101                if (N.y() > N.x() && N.y() > N.z()) axis = 1;
102                if (-N.y() > N.x() && -N.y() > N.z()) axis = 1;
103                if (N.z() > N.x() && N.z() > N.y()) axis = 2;
104                if (-N.z() > N.x() && -N.z() > N.y()) axis = 2;
105
106                osg::Vec2 uv;
107
108                switch (axis) {
109                    case 0: uv.set(P.y(), P.z()); break;
110                    case 1: uv.set(P.x(), P.z()); break;
111                    case 2: uv.set(P.x(), P.y()); break;
112                    default: ;
113                }
114
115                tc->push_back(uv * scale);
116            }
117            return tc.release();
118        }
119
120    private:
121        int du_;
122        int nu_;
123    };
124
125}
126
127namespace
128{
129
130    const unsigned int NO_VALID_CONTEXT = 0xffffffff;
131
132    // a state attribute class that grabs the initial inverse view matrix
133    // and sends it to a VertexProgram.
134    // NOTE: due to lack of support for per-context parameters in VertexProgram,
135    // this class will send the matrix to the vp only while the first context
136    // is being rendered. All subsequent contexts will use the first context's
137    // matrix.
138    class ViewMatrixExtractor: public osg::StateAttribute {
139    public:
140
141
142        ViewMatrixExtractor()
143        :    osg::StateAttribute(),
144            _vp(0),
145            _param(0),
146            _first_context(NO_VALID_CONTEXT)
147        {
148        }
149
150        ViewMatrixExtractor(const ViewMatrixExtractor& copy, const osg::CopyOp& copyop)
151        :    osg::StateAttribute(copy, copyop),
152            _vp(static_cast<osg::VertexProgram* >(copyop(copy._vp.get()))),
153            _param(copy._param),
154            _first_context(NO_VALID_CONTEXT)
155        {
156        }
157
158        ViewMatrixExtractor(osg::VertexProgram* vp, int param)
159        :    osg::StateAttribute(),
160            _vp(vp),
161            _param(param),
162            _first_context(NO_VALID_CONTEXT)
163        {
164        }
165
166        META_StateAttribute(osgFX, ViewMatrixExtractor, VIEWMATRIXEXTRACTOR);
167
168        int compare(const osg::StateAttribute& sa) const
169        {
170            COMPARE_StateAttribute_Types(ViewMatrixExtractor, sa);
171            if (_vp.get() != rhs._vp.get()) return -1;
172            if (_param < rhs._param) return -1;
173            if (_param > rhs._param) return 1;
174            return 0;
175        }
176
177        void apply(osg::State& state) const
178        {
179            if (_first_context == NO_VALID_CONTEXT) {
180                _first_context = state.getContextID();
181            }
182            if (state.getContextID() == _first_context) {
183                if (_vp.valid()) {
184                    osg::Matrix M = state.getInitialInverseViewMatrix();
185                    for (int i=0; i<4; ++i) {
186                        _vp->setProgramLocalParameter(_param+i, osg::Vec4(M(0, i), M(1, i), M(2, i), M(3, i)));
187                    }
188                }
189            }
190        }
191
192    private:
193        mutable osg::ref_ptr<osg::VertexProgram> _vp;
194        int _param;
195        mutable unsigned int _first_context;
196    };
197
198}
199
200
201namespace
202{
203    // let's register this cool effect! :)
204    Registry::Proxy proxy(new BumpMapping);
205}
206
207
208namespace
209{
210
211    // "Full ARB" technique uses ARB vertex program and fragment program.
212    // Handles ambient, diffuse and specular lighting transparently. A texture
213    // for the diffuse component is required as well as a normal map texture.
214    class FullArbTechnique: public Technique {
215    public:
216
217        FullArbTechnique(int lightnum, int diffuseunit, int normalunit, osg::Texture2D* diffuse_tex, osg::Texture2D* normal_tex)
218        :   Technique(),
219            _lightnum(lightnum),
220            _diffuse_unit(diffuseunit),
221            _normal_unit(normalunit),
222            _diffuse_tex(diffuse_tex),
223            _normal_tex(normal_tex)
224        {
225        }
226
227        META_Technique(
228            "FullArbTechnique",
229            "Single-pass technique, requires ARB_vertex_program and ARB_fragment_program."
230        );
231
232        void getRequiredExtensions(std::vector<std::string>& extensions) const
233        {
234            extensions.push_back("GL_ARB_vertex_program");
235            extensions.push_back("GL_ARB_fragment_program");
236        }
237
238    protected:
239
240        void define_passes()
241        {
242            int freeunit;
243            for (freeunit=0; freeunit==_diffuse_unit||freeunit==_normal_unit; ++freeunit) {}
244
245            // vertex program
246            std::ostringstream vp_oss;
247            vp_oss <<
248                "!!ARBvp1.0\n"
249                "OPTION ARB_position_invariant;"
250                "PARAM c4 = { 0, 0, 0, 1 };"
251                "PARAM c5 = { 0.5, 4, 0, 0 };"
252                "TEMP R0, R1, R2, R3, R4, R5, R6, R7, R8;"
253                "ATTRIB v5 = vertex.attrib[15];"
254                "ATTRIB v4 = vertex.attrib[7];"
255                "ATTRIB v3 = vertex.attrib[6];"
256                "ATTRIB v25 = vertex.texcoord[" << _diffuse_unit << "];"
257                "ATTRIB v24 = vertex.texcoord[" << _normal_unit << "];"
258                "ATTRIB v18 = vertex.normal;"
259                "ATTRIB v16 = vertex.position;"
260                "PARAM s259[4] = { state.matrix.mvp };"
261                "PARAM s18 = state.light[0].position;"
262                "PARAM s77 = state.lightprod[0].specular;"
263                "PARAM s4 = state.material.shininess;"
264                "PARAM s75 = state.lightprod[0].ambient;"
265                "PARAM s223[4] = { state.matrix.modelview };"
266                "PARAM c0[4] = { program.local[0..3] };"
267                "    MOV result.texcoord[" << freeunit << "].xyz, s75.xyzx;"
268                "    MOV result.texcoord[" << freeunit << "].w, s4.x;"
269                "    MOV result.texcoord[" << _normal_unit << "].zw, s77.zwzw;"
270                "    MOV result.texcoord[" << _normal_unit << "].xy, v24;"
271                "    MOV result.texcoord[" << _diffuse_unit << "].zw, s77.xyxy;"
272                "    MOV result.texcoord[" << _diffuse_unit << "].xy, v25;"
273                "    MOV R5, c0[0];"
274                "    MUL R0, R5.y, s223[1];"
275                "    MAD R0, R5.x, s223[0], R0;"
276                "    MAD R0, R5.z, s223[2], R0;"
277                "    MAD R0, R5.w, s223[3], R0;"
278                "    DP4 R1.x, R0, v16;"
279                "    MOV R4, c0[1];"
280                "    MUL R2, R4.y, s223[1];"
281                "    MAD R2, R4.x, s223[0], R2;"
282                "    MAD R2, R4.z, s223[2], R2;"
283                "    MAD R7, R4.w, s223[3], R2;"
284                "    DP4 R1.y, R7, v16;"
285                "    MOV R3, c0[2];"
286                "    MUL R2, R3.y, s223[1];"
287                "    MAD R2, R3.x, s223[0], R2;"
288                "    MAD R2, R3.z, s223[2], R2;"
289                "    MAD R6, R3.w, s223[3], R2;"
290                "    DP4 R1.z, R6, v16;"
291                "    MOV R2, c0[3];"
292                "    MUL R8, R2.y, s223[1];"
293                "    MAD R8, R2.x, s223[0], R8;"
294                "    MAD R8, R2.z, s223[2], R8;"
295                "    MAD R8, R2.w, s223[3], R8;"
296                "    MOV R8.x, R5.w;"
297                "    MOV R8.y, R4.w;"
298                "    MOV R8.z, R3.w;"
299                "    ADD R1.yzw, R8.xxyz, -R1.xxyz;"
300                "    DP3 R1.x, R1.yzwy, R1.yzwy;"
301                "    RSQ R1.x, R1.x;"
302                "    DP4 R5.x, R5, s18;"
303                "    DP4 R5.y, R4, s18;"
304                "    DP4 R5.z, R3, s18;"
305                "    DP3 R2.x, R5.xyzx, R5.xyzx;"
306                "    RSQ R2.x, R2.x;"
307                "    MUL R5.xyz, R2.x, R5.xyzx;"
308                "    MAD R1.yzw, R1.x, R1.yyzw, R5.xxyz;"
309                "    DP3 R1.x, R1.yzwy, R1.yzwy;"
310                "    RSQ R1.x, R1.x;"
311                "    MUL R4.xyz, R1.x, R1.yzwy;"
312                "    DP3 R3.x, R0.xyzx, v3.xyzx;"
313                "    DP3 R3.y, R7.xyzx, v3.xyzx;"
314                "    DP3 R3.z, R6.xyzx, v3.xyzx;"
315                "    DP3 R8.x, R3.xyzx, R4.xyzx;"
316                "    DP3 R2.x, R0.xyzx, v4.xyzx;"
317                "    DP3 R2.y, R7.xyzx, v4.xyzx;"
318                "    DP3 R2.z, R6.xyzx, v4.xyzx;"
319                "    DP3 R8.y, R2.xyzx, R4.xyzx;"
320                "    DP3 R1.x, R0.xyzx, v5.xyzx;"
321                "    DP3 R1.y, R7.xyzx, v5.xyzx;"
322                "    DP3 R1.z, R6.xyzx, v5.xyzx;"
323                "    DP3 R8.z, R1.xyzx, R4.xyzx;"
324                "    MAD result.color.front.secondary.xyz, c5.x, R8.xyzx, c5.x;"
325                "    DP3 R0.y, R0.xyzx, v18.xyzx;"
326                "    DP3 R0.z, R7.xyzx, v18.xyzx;"
327                "    DP3 R0.w, R6.xyzx, v18.xyzx;"
328                "    DP3 R0.x, R0.yzwy, R0.yzwy;"
329                "    RSQ R0.x, R0.x;"
330                "    MUL R6.xyz, R0.x, R0.yzwy;"
331                "    DP3 R0.x, R6.xyzx, R4.xyzx;"
332                "    MUL result.color.front.secondary.w, c5.y, R0.x;"
333                "    DP3 R0.x, R3.xyzx, R5.xyzx;"
334                "    DP3 R0.y, R2.xyzx, R5.xyzx;"
335                "    DP3 R0.z, R1.xyzx, R5.xyzx;"
336                "    MAD result.color.front.primary.xyz, c5.x, R0.xyzx, c5.x;"
337                "    DP3 R0.x, R6.xyzx, R5.xyzx;"
338                "    MUL result.color.front.primary.w, c5.y, R0.x;"
339                "END\n";
340
341            // fragment program
342            std::ostringstream fp_oss;
343            fp_oss <<
344                "!!ARBfp1.0\n"
345                "PARAM c0 = {1, 2, 0.5, 0};"
346                "PARAM c1 = {0, 0, 0, 1};"
347                "TEMP R0;"
348                "TEMP R1;"
349                "TEMP R2;"
350                "TEX R0, fragment.texcoord[" << _normal_unit << "], texture[" << _normal_unit << "], 2D;"
351                "TEX R1, fragment.texcoord[" << _diffuse_unit << "], texture[" << _diffuse_unit << "], 2D;"
352                "ADD R0, R0, -c0.z;"
353                "MUL R0.xyz, c0.y, R0;"
354                "ADD R2.xyz, fragment.color.primary, -c0.z;"
355                "MUL R2.xyz, c0.y, R2;"
356                "DP3_SAT R0.w, R0, R2;"
357                "ADD R2, fragment.color.secondary, -c0.z;"
358                "MUL R2.xyz, c0.y, R2;"
359                "DP3_SAT R0.x, R0, R2;"
360                "POW R0.x, R0.x, fragment.texcoord[" << freeunit << "].w;"
361                "MOV R2.xyz, fragment.texcoord[" << freeunit << "].xyyx;"
362                "MOV R2.w, c1.w;"
363                "MOV_SAT R0.y, fragment.color.primary.w;"
364                "MUL R0.w, R0.y, R0.w;"
365                "ADD R2, R2, R0.w;"
366                "MUL R1.xyz, R1, R2;"
367                "MOV_SAT R0.y, fragment.color.secondary.w;"
368                "MUL R0.xyz, R0.y, R0.x;"
369                "MOV R2.xy, fragment.texcoord[" << _diffuse_unit << "].zwzz;"
370                "MOV R2.z, fragment.texcoord[" << _normal_unit << "].z;"
371                "MUL R2.xyz, R0, R2;"
372                "ADD R2.xyz, R1, R2;"
373                "MOV result.color.xyz, R2;"
374                "MOV result.color.w, c0.x;"
375                "END\n";
376
377            osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
378
379            osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram;
380            vp->setVertexProgram(vp_oss.str());
381            ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
382
383            osg::ref_ptr<osg::FragmentProgram> fp = new osg::FragmentProgram;
384            fp->setFragmentProgram(fp_oss.str());
385            ss->setAttributeAndModes(fp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
386
387            ss->setAttributeAndModes(new ViewMatrixExtractor(vp.get(), 0), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
388
389            if (_diffuse_tex.valid()) {
390                ss->setTextureAttributeAndModes(_diffuse_unit, _diffuse_tex.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
391            }
392
393            if (_normal_tex.valid()) {
394                ss->setTextureAttributeAndModes(_normal_unit, _normal_tex.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
395            }
396
397            addPass(ss.get());
398        }
399
400    private:
401        int _lightnum;
402        int _diffuse_unit;
403        int _normal_unit;
404        osg::ref_ptr<osg::Texture2D> _diffuse_tex;
405        osg::ref_ptr<osg::Texture2D> _normal_tex;
406    };
407
408}
409
410namespace
411{
412
413    // "ARB Vp" technique uses ARB vertex program and DOT3 texture environment.
414    // Ambient and specular components are not handled. A texture for the diffuse
415    // component is required as well as a normal map texture.
416    class ArbVpTechnique: public Technique {
417    public:
418        ArbVpTechnique(int lightnum, int diffuseunit, int normalunit, osg::Texture2D* diffuse_tex, osg::Texture2D* normal_tex)
419        :   Technique(),
420            _lightnum(lightnum),
421            _diffuse_unit(diffuseunit),
422            _normal_unit(normalunit),
423            _diffuse_tex(diffuse_tex),
424            _normal_tex(normal_tex)
425        {
426        }
427
428        META_Technique(
429            "ArbVpTechnique",
430            "Two-passes technique, requires ARB_vertex_program and ARB__textureenv_dot3."
431            "Only diffuse lighting, no ambient, no specularity."
432        );
433
434        void getRequiredExtensions(std::vector<std::string>& extensions) const
435        {
436            extensions.push_back("GL_ARB_vertex_program");
437            extensions.push_back("GL_ARB_texture_env_dot3");
438        }
439
440        void define_passes()
441        {
442            if (_diffuse_unit != (_normal_unit + 1)) {
443                OSG_WARN << "Warning: osgFX::BumpMapping: this technique (ArbVpTechnique) requires that _diffuse_unit == (_normal_unit + 1). Effect may not show up properly.\n";
444            }
445
446            // first pass, diffuse bump
447            {
448                std::ostringstream vp_oss;
449                vp_oss <<
450                    "!!ARBvp1.0\n"
451                    "OPTION ARB_position_invariant;"
452                    "PARAM c0 = { 0.5, 1, 0, 0 };"
453                    "TEMP R0, R1, R2;"
454                    "ATTRIB v5 = vertex.attrib[15];"
455                    "ATTRIB v4 = vertex.attrib[7];"
456                    "ATTRIB v3 = vertex.attrib[6];"
457                    "ATTRIB v24 = vertex.texcoord[" << _normal_unit << "];"
458                    "ATTRIB v25 = vertex.texcoord[" << _diffuse_unit << "];"
459                    "ATTRIB v18 = vertex.normal;"
460                    "ATTRIB v16 = vertex.position;"
461                    "PARAM s259[4] = { state.matrix.mvp };"
462                    "PARAM s18 = state.light[" << _lightnum << "].position;"
463                    "PARAM s223[4] = { state.matrix.modelview };"
464                    "    MOV result.texcoord[" << _diffuse_unit << "].xy, v25;"
465                    "    MOV result.texcoord[" << _normal_unit << "].xy, v24;"
466                    "    DP3 R0.y, s223[0].xyzx, v3.xyzx;"
467                    "    DP3 R0.z, s223[1].xyzx, v3.xyzx;"
468                    "    DP3 R0.w, s223[2].xyzx, v3.xyzx;"
469                    "    DP3 R0.x, s18.xyzx, s18.xyzx;"
470                    "    RSQ R0.x, R0.x;"
471                    "    MUL R2.xyz, R0.x, s18.xyzx;"
472                    "    DP3 R1.x, R0.yzwy, R2.xyzx;"
473                    "    DP3 R0.x, s223[0].xyzx, v4.xyzx;"
474                    "    DP3 R0.y, s223[1].xyzx, v4.xyzx;"
475                    "    DP3 R0.z, s223[2].xyzx, v4.xyzx;"
476                    "    DP3 R1.y, R0.xyzx, R2.xyzx;"
477                    "    DP3 R0.x, s223[0].xyzx, v5.xyzx;"
478                    "    DP3 R0.y, s223[1].xyzx, v5.xyzx;"
479                    "    DP3 R0.z, s223[2].xyzx, v5.xyzx;"
480                    "    DP3 R1.z, R0.xyzx, R2.xyzx;"
481                    "    MAD result.color.front.primary.xyz, c0.x, R1.xyzx, c0.x;"
482                    "    MOV result.color.front.primary.w, c0.y;"
483                    "END\n";
484
485                osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
486
487                osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram;
488                vp->setVertexProgram(vp_oss.str());
489                ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
490
491                if (_diffuse_tex.valid()) {
492                    ss->setTextureAttributeAndModes(_diffuse_unit, _diffuse_tex.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
493                }
494
495                if (_normal_tex.valid()) {
496                    ss->setTextureAttributeAndModes(_normal_unit, _normal_tex.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
497                }
498
499                osg::ref_ptr<osg::TexEnvCombine> tec = new osg::TexEnvCombine;
500                tec->setCombine_RGB(osg::TexEnvCombine::DOT3_RGB);
501                tec->setSource0_RGB(osg::TexEnvCombine::PRIMARY_COLOR);
502                tec->setSource1_RGB(osg::TexEnvCombine::TEXTURE);
503                ss->setTextureAttributeAndModes(_normal_unit, tec.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
504
505                osg::ref_ptr<osg::TexEnv> te = new osg::TexEnv;
506                te->setMode(osg::TexEnv::MODULATE);
507                ss->setTextureAttributeAndModes(_diffuse_unit, te.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
508
509                addPass(ss.get());
510            }
511
512            // second pass, self-shadowing
513            bool selfShadowing = false;
514            if (selfShadowing)
515            {
516                std::ostringstream vp_oss;
517                vp_oss <<
518                    "!!ARBvp1.0\n"
519                    "OPTION ARB_position_invariant;"
520                    "PARAM c0 = { 8, 0, 1, 0 };"
521                    "TEMP R0;"
522                    "ATTRIB v18 = vertex.normal;"
523                    "ATTRIB v16 = vertex.position;"
524                    "PARAM s259[4] = { state.matrix.mvp };"
525                    "PARAM s18 = state.light[" << _lightnum << "].position;"
526                    "PARAM s631[4] = { state.matrix.modelview.invtrans };"
527                    "    DP4 R0.x, s631[0], v18;"
528                    "    DP4 R0.y, s631[1], v18;"
529                    "    DP4 R0.z, s631[2], v18;"
530                    "    DP3 R0.x, R0.xyzx, s18.xyzx;"
531                    "    MAX R0.x, R0.x, c0.y;"
532                    "    MUL R0.x, c0.x, R0.x;"
533                    "    MIN result.color.front.primary.xyz, R0.x, c0.z;"
534                    "    MOV result.color.front.primary.w, c0.z;"
535                    "END\n";
536
537                osg::ref_ptr<osg::StateSet> ss = new osg::StateSet;
538
539                osg::ref_ptr<osg::Depth> depth = new osg::Depth;
540                depth->setFunction(osg::Depth::EQUAL);
541                ss->setAttributeAndModes(depth.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
542
543                osg::ref_ptr<osg::VertexProgram> vp = new osg::VertexProgram;
544                vp->setVertexProgram(vp_oss.str());
545                ss->setAttributeAndModes(vp.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
546
547                osg::ref_ptr<osg::BlendFunc> bf = new osg::BlendFunc;
548                bf->setFunction(osg::BlendFunc::DST_COLOR, osg::BlendFunc::ZERO);
549                ss->setAttributeAndModes(bf.get(), osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
550
551                ss->setTextureMode(_diffuse_unit, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
552                ss->setTextureMode(_normal_unit, GL_TEXTURE_2D, osg::StateAttribute::OVERRIDE|osg::StateAttribute::OFF);
553
554                addPass(ss.get());
555            }
556
557        }
558
559    protected:
560        int _lightnum;
561        int _diffuse_unit;
562        int _normal_unit;
563        osg::ref_ptr<osg::Texture2D> _diffuse_tex;
564        osg::ref_ptr<osg::Texture2D> _normal_tex;
565    };
566
567}
568
569
570BumpMapping::BumpMapping()
571:   Effect(),
572    _lightnum(0),
573    _diffuse_unit(1),
574    _normal_unit(0)
575{
576}
577
578BumpMapping::BumpMapping(const BumpMapping& copy, const osg::CopyOp& copyop)
579:   Effect(copy, copyop),
580    _lightnum(copy._lightnum),
581    _diffuse_unit(copy._diffuse_unit),
582    _normal_unit(copy._normal_unit),
583    _diffuse_tex(static_cast<osg::Texture2D* >(copyop(copy._diffuse_tex.get()))),
584    _normal_tex(static_cast<osg::Texture2D* >(copyop(copy._normal_tex.get())))
585{
586}
587
588bool BumpMapping::define_techniques()
589{
590    addTechnique(new FullArbTechnique(_lightnum, _diffuse_unit, _normal_unit, _diffuse_tex.get(), _normal_tex.get()));
591    addTechnique(new ArbVpTechnique(_lightnum, _diffuse_unit, _normal_unit, _diffuse_tex.get(), _normal_tex.get()));
592    return true;
593}
594
595void BumpMapping::prepareGeometry(osg::Geometry* geo)
596{
597    osg::ref_ptr<osgUtil::TangentSpaceGenerator> tsg = new osgUtil::TangentSpaceGenerator;
598    tsg->generate(geo, _normal_unit);
599    if (!geo->getVertexAttribArray(6))
600        geo->setVertexAttribData(6, osg::Geometry::ArrayData(tsg->getTangentArray(), osg::Geometry::BIND_PER_VERTEX,GL_FALSE));
601    if (!geo->getVertexAttribArray(7))
602        geo->setVertexAttribData(7, osg::Geometry::ArrayData(tsg->getBinormalArray(), osg::Geometry::BIND_PER_VERTEX, GL_FALSE));
603    if (!geo->getVertexAttribArray(15))
604        geo->setVertexAttribData(15, osg::Geometry::ArrayData(tsg->getNormalArray(), osg::Geometry::BIND_PER_VERTEX, GL_FALSE));
605}
606
607void BumpMapping::prepareNode(osg::Node* node)
608{
609    osg::ref_ptr<TsgVisitor> tv = new TsgVisitor(this);
610    node->accept(*tv.get());
611}
612
613void BumpMapping::prepareChildren()
614{
615    for (unsigned i=0; i<getNumChildren(); ++i)
616        prepareNode(getChild(i));
617}
618
619void BumpMapping::setUpDemo()
620{
621    // generate texture coordinates
622    TexCoordGenerator tcg(_diffuse_unit, _normal_unit);
623    for (unsigned i=0; i<getNumChildren(); ++i)
624        getChild(i)->accept(tcg);
625
626    // set up diffuse texture
627    if (!_diffuse_tex.valid()) {
628        _diffuse_tex = new osg::Texture2D;
629        _diffuse_tex->setImage(osgDB::readImageFile("Images/whitemetal_diffuse.jpg"));
630        _diffuse_tex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
631        _diffuse_tex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
632        _diffuse_tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
633        _diffuse_tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
634        _diffuse_tex->setMaxAnisotropy(8);
635    }
636
637    // set up normal map texture
638    if (!_normal_tex.valid()) {
639        _normal_tex = new osg::Texture2D;
640        _normal_tex->setImage(osgDB::readImageFile("Images/whitemetal_normal.jpg"));
641        _normal_tex->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
642        _normal_tex->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
643        _normal_tex->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
644        _normal_tex->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);
645        _normal_tex->setMaxAnisotropy(8);
646    }
647
648    // generate tangent-space basis vector
649    prepareChildren();
650
651    // recreate techniques on next step
652    dirtyTechniques();
653}
Note: See TracBrowser for help on using the browser.