root/OpenSceneGraph/trunk/examples/osgvertexprogram/osgvertexprogram.cpp @ 13295

Revision 8868, 17.4 kB (checked in by robert, 6 years ago)

From Mathias Froehlich, "This is a generic optimization that does not depend on any cpu or instruction
set.

The optimization is based on the observation that matrix matrix multiplication
with a dense matrix 4x4 is 43 Operations whereas multiplication with a
transform, or scale matrix is only 4
2 operations. Which is a gain of a
*FACTOR*4* for these special cases.
The change implements these special cases, provides a unit test for these
implementation and converts uses of the expensiver dense matrix matrix
routine with the specialized versions.

Depending on the transform nodes in the scenegraph this change gives a
noticable improovement.
For example the osgforest code using the MatrixTransform? is about 20% slower
than the same codepath using the PositionAttitudeTransform? instead of the
MatrixTransform? with this patch applied.

If I remember right, the sse type optimizations did *not* provide a factor 4
improovement. Also these changes are totally independent of any cpu or
instruction set architecture. So I would prefer to have this current kind of
change instead of some hand coded and cpu dependent assembly stuff. If we
need that hand tuned stuff, these can go on top of this changes which must
provide than hand optimized additional variants for the specialized versions
to give a even better result in the end.

An other change included here is a change to rotation matrix from quaterion
code. There is a sqrt call which couold be optimized away. Since we divide in
effect by sqrt(length)*sqrt(length) which is just length ...
"

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* OpenSceneGraph example, osgvertexprogram.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include <osg/Vec3>
20#include <osg/Vec4>
21#include <osg/Quat>
22#include <osg/Matrix>
23#include <osg/ShapeDrawable>
24#include <osg/Geometry>
25#include <osg/Geode>
26#include <osg/Transform>
27#include <osg/Material>
28#include <osg/NodeCallback>
29#include <osg/Depth>
30#include <osg/CullFace>
31#include <osg/TexMat>
32#include <osg/TexGen>
33#include <osg/TexEnv>
34#include <osg/TexEnvCombine>
35#include <osg/TextureCubeMap>
36#include <osg/VertexProgram>
37
38#include <osgDB/Registry>
39#include <osgDB/ReadFile>
40
41#include <osgUtil/SmoothingVisitor>
42#include <osgUtil/Optimizer>
43
44#include <osgViewer/Viewer>
45
46#include <iostream>
47
48
49float refract = 1.02;          // ratio of indicies of refraction
50float fresnel = 0.2;           // Fresnel multiplier
51
52
53const char vpstr[] =
54    "!!ARBvp1.0 # Refraction                                    \n"
55    "                                                           \n"
56    "ATTRIB iPos         = vertex.position;                     \n"
57    "#ATTRIB iCol        = vertex.color.primary;                \n"
58    "ATTRIB iNormal      = vertex.normal;                       \n"
59    "PARAM  esEyePos     = { 0, 0, 0, 1 };                      \n"
60    "PARAM  const0123    = { 0, 1, 2, 3 };                      \n"
61    "PARAM  fresnel      = program.local[0];                    \n"
62    "PARAM  refract      = program.local[1];                    \n"
63    "PARAM  itMV[4]      = { state.matrix.modelview.invtrans }; \n"
64    "PARAM  MVP[4]       = { state.matrix.mvp };                \n"
65    "PARAM  MV[4]        = { state.matrix.modelview };          \n"
66    "PARAM  texmat[4]    = { state.matrix.texture[0] };         \n"
67    "TEMP   esPos;        # position in eye-space               \n"
68    "TEMP   esNormal;     # normal in eye-space                 \n"
69    "TEMP   tmp, IdotN, K;                                      \n"
70    "TEMP   esE;          # eye vector                          \n"
71    "TEMP   esI;          # incident vector (=-E)               \n"
72    "TEMP   esR;          # first refract- then reflect-vector  \n"
73    "OUTPUT oPos         = result.position;                     \n"
74    "OUTPUT oColor       = result.color;                        \n"
75    "OUTPUT oRefractMap  = result.texcoord[0];                  \n"
76    "OUTPUT oReflectMap  = result.texcoord[1];                  \n"
77    "                                                           \n"
78    "# transform vertex to clip space                           \n"
79    "DP4    oPos.x, MVP[0], iPos;                               \n"
80    "DP4    oPos.y, MVP[1], iPos;                               \n"
81    "DP4    oPos.z, MVP[2], iPos;                               \n"
82    "DP4    oPos.w, MVP[3], iPos;                               \n"
83    "                                                           \n"
84    "# Transform the normal to eye space.                       \n"
85    "DP3    esNormal.x, itMV[0], iNormal;                       \n"
86    "DP3    esNormal.y, itMV[1], iNormal;                       \n"
87    "DP3    esNormal.z, itMV[2], iNormal;                       \n"
88    "                                                           \n"
89    "# normalize normal                                         \n"
90    "DP3    esNormal.w, esNormal, esNormal;                     \n"
91    "RSQ    esNormal.w, esNormal.w;                             \n"
92    "MUL    esNormal, esNormal, esNormal.w;                     \n"
93    "                                                           \n"
94    "# transform vertex position to eye space                   \n"
95    "DP4    esPos.x, MV[0], iPos;                               \n"
96    "DP4    esPos.y, MV[1], iPos;                               \n"
97    "DP4    esPos.z, MV[2], iPos;                               \n"
98    "DP4    esPos.w, MV[3], iPos;                               \n"
99    "                                                           \n"
100    "# vertex to eye vector                                     \n"
101    "ADD    esE, -esPos, esEyePos;                              \n"
102    "#MOV   esE, -esPos;                                        \n"
103    "                                                           \n"
104    "# normalize eye vector                                     \n"
105    "DP3    esE.w, esE, esE;                                    \n"
106    "RSQ    esE.w, esE.w;                                       \n"
107    "MUL    esE, esE, esE.w;                                    \n"
108    "                                                           \n"
109    "# calculate some handy values                              \n"
110    "MOV    esI, -esE;                                          \n"
111    "DP3    IdotN, esNormal, esI;                               \n"
112    "                                                           \n"
113    "# calculate refraction vector, Renderman style             \n"
114    "                                                           \n"
115    "# k = 1-index*index*(1-(I dot N)^2)                        \n"
116    "MAD    tmp, -IdotN, IdotN, const0123.y;                    \n"
117    "MUL    tmp, tmp, refract.y;                                \n"
118    "ADD    K.x, const0123.y, -tmp;                             \n"
119    "                                                           \n"
120    "# k<0,  R = [0,0,0]                                        \n"
121    "# k>=0, R = index*I-(index*(I dot N) + sqrt(k))*N          \n"
122    "RSQ    K.y, K.x;                                           \n"
123    "RCP    K.y, K.y;                           # K.y = sqrt(k) \n"
124    "MAD    tmp.x, refract.x, IdotN, K.y;                       \n"
125    "MUL    tmp, esNormal, tmp.x;                               \n"
126    "MAD    esR, refract.x, esI, tmp;                           \n"
127    "                                                           \n"
128    "# transform refracted ray by cubemap transform             \n"
129    "DP3    oRefractMap.x, texmat[0], esR;                      \n"
130    "DP3    oRefractMap.y, texmat[1], esR;                      \n"
131    "DP3    oRefractMap.z, texmat[2], esR;                      \n"
132    "                                                           \n"
133    "# calculate reflection vector                              \n"
134    "# R = 2*N*(N dot E)-E                                      \n"
135    "MUL    tmp, esNormal, const0123.z;                         \n"
136    "DP3    esR.w, esNormal, esE;                               \n"
137    "MAD    esR, esR.w, tmp, -esE;                              \n"
138    "                                                           \n"
139    "# transform reflected ray by cubemap transform             \n"
140    "DP3    oReflectMap.x, texmat[0], esR;                      \n"
141    "DP3    oReflectMap.y, texmat[1], esR;                      \n"
142    "DP3    oReflectMap.z, texmat[2], esR;                      \n"
143    "                                                           \n"
144    "# Fresnel approximation = fresnel*(1-(N dot I))^2          \n"
145    "ADD    tmp.x, const0123.y, -IdotN;                         \n"
146    "MUL    tmp.x, tmp.x, tmp.x;                                \n"
147    "MUL    oColor, tmp.x, fresnel;                             \n"
148    "                                                           \n"
149    "END                                                        \n";
150
151
152osg::TextureCubeMap* readCubeMap()
153{
154    osg::TextureCubeMap* cubemap = new osg::TextureCubeMap;
155    //#define CUBEMAP_FILENAME(face) "nvlobby_" #face ".png"
156    //#define CUBEMAP_FILENAME(face) "Cubemap_axis/" #face ".png"
157    #define CUBEMAP_FILENAME(face) "Cubemap_snow/" #face ".jpg"
158
159    osg::Image* imagePosX = osgDB::readImageFile(CUBEMAP_FILENAME(posx));
160    osg::Image* imageNegX = osgDB::readImageFile(CUBEMAP_FILENAME(negx));
161    osg::Image* imagePosY = osgDB::readImageFile(CUBEMAP_FILENAME(posy));
162    osg::Image* imageNegY = osgDB::readImageFile(CUBEMAP_FILENAME(negy));
163    osg::Image* imagePosZ = osgDB::readImageFile(CUBEMAP_FILENAME(posz));
164    osg::Image* imageNegZ = osgDB::readImageFile(CUBEMAP_FILENAME(negz));
165
166    if (imagePosX && imageNegX && imagePosY && imageNegY && imagePosZ && imageNegZ)
167    {
168        cubemap->setImage(osg::TextureCubeMap::POSITIVE_X, imagePosX);
169        cubemap->setImage(osg::TextureCubeMap::NEGATIVE_X, imageNegX);
170        cubemap->setImage(osg::TextureCubeMap::POSITIVE_Y, imagePosY);
171        cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Y, imageNegY);
172        cubemap->setImage(osg::TextureCubeMap::POSITIVE_Z, imagePosZ);
173        cubemap->setImage(osg::TextureCubeMap::NEGATIVE_Z, imageNegZ);
174
175        cubemap->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
176        cubemap->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
177        cubemap->setWrap(osg::Texture::WRAP_R, osg::Texture::CLAMP_TO_EDGE);
178
179        cubemap->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR_MIPMAP_LINEAR);
180        cubemap->setFilter(osg::Texture::MAG_FILTER, osg::Texture::LINEAR);
181    }
182
183    return cubemap;
184}
185
186
187// Update texture matrix for cubemaps
188struct TexMatCallback : public osg::NodeCallback
189{
190public:
191
192    TexMatCallback(osg::TexMat& tm) :
193        _texMat(tm)
194    {
195    }
196
197    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
198    {
199        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
200        if (cv)
201        {
202            const osg::Matrix& MV = *(cv->getModelViewMatrix());
203            const osg::Matrix R = osg::Matrix::rotate( osg::DegreesToRadians(112.0f), 0.0f,0.0f,1.0f)*
204                                  osg::Matrix::rotate( osg::DegreesToRadians(90.0f), 1.0f,0.0f,0.0f);
205
206            osg::Quat q = MV.getRotate();
207            const osg::Matrix C = osg::Matrix::rotate( q.inverse() );
208
209            _texMat.setMatrix( C*R );
210        }
211
212        traverse(node,nv);
213    }
214
215    osg::TexMat& _texMat;
216};
217
218
219class MoveEarthySkyWithEyePointTransform : public osg::Transform
220{
221public:
222    /** Get the transformation matrix which moves from local coords to world coords.*/
223    virtual bool computeLocalToWorldMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const 
224    {
225        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
226        if (cv)
227        {
228            osg::Vec3 eyePointLocal = cv->getEyeLocal();
229            matrix.preMultTranslate(eyePointLocal);
230        }
231        return true;
232    }
233
234    /** Get the transformation matrix which moves from world coords to local coords.*/
235    virtual bool computeWorldToLocalMatrix(osg::Matrix& matrix,osg::NodeVisitor* nv) const
236    {
237        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
238        if (cv)
239        {
240            osg::Vec3 eyePointLocal = cv->getEyeLocal();
241            matrix.postMultTranslate(-eyePointLocal);
242        }
243        return true;
244    }
245};
246
247
248osg::Node* createSkyBox()
249{
250
251    osg::StateSet* stateset = new osg::StateSet();
252
253    osg::TexEnv* te = new osg::TexEnv;
254    te->setMode(osg::TexEnv::REPLACE);
255    stateset->setTextureAttributeAndModes(0, te, osg::StateAttribute::ON);
256
257    osg::TexGen *tg = new osg::TexGen;
258    tg->setMode(osg::TexGen::NORMAL_MAP);
259    stateset->setTextureAttributeAndModes(0, tg, osg::StateAttribute::ON);
260
261    osg::TexMat *tm = new osg::TexMat;
262    stateset->setTextureAttribute(0, tm);
263
264    osg::TextureCubeMap* skymap = readCubeMap();
265    stateset->setTextureAttributeAndModes(0, skymap, osg::StateAttribute::ON);
266
267    stateset->setMode( GL_LIGHTING, osg::StateAttribute::OFF );
268    stateset->setMode( GL_CULL_FACE, osg::StateAttribute::OFF );
269
270    // clear the depth to the far plane.
271    osg::Depth* depth = new osg::Depth;
272    depth->setFunction(osg::Depth::ALWAYS);
273    depth->setRange(1.0,1.0);   
274    stateset->setAttributeAndModes(depth, osg::StateAttribute::ON );
275
276    stateset->setRenderBinDetails(-1,"RenderBin");
277
278    osg::Drawable* drawable = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f,0.0f,0.0f),1));
279
280    osg::Geode* geode = new osg::Geode;
281    geode->setCullingActive(false);
282    geode->setStateSet( stateset );
283    geode->addDrawable(drawable);
284
285
286    osg::Transform* transform = new MoveEarthySkyWithEyePointTransform;
287    transform->setCullingActive(false);
288    transform->addChild(geode);
289
290    osg::ClearNode* clearNode = new osg::ClearNode;
291//  clearNode->setRequiresClear(false);
292    clearNode->setCullCallback(new TexMatCallback(*tm));
293    clearNode->addChild(transform);
294
295    return clearNode;
296}
297
298
299
300
301osg::Node* addRefractStateSet(osg::Node* node)
302{
303    osg::StateSet* stateset = new osg::StateSet();
304
305    osg::TextureCubeMap* reflectmap = readCubeMap();
306    stateset->setTextureAttributeAndModes( 0, reflectmap, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
307    stateset->setTextureAttributeAndModes( 1, reflectmap, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
308   
309    osg::TexMat* texMat = new osg::TexMat;
310    stateset->setTextureAttribute(0, texMat);
311
312    // ---------------------------------------------------
313    // Vertex Program
314    // ---------------------------------------------------
315    osg::VertexProgram* vp = new osg::VertexProgram();
316    vp->setVertexProgram( vpstr );
317    vp->setProgramLocalParameter( 0, osg::Vec4( fresnel, fresnel, fresnel, 1.0f ) );
318    vp->setProgramLocalParameter( 1, osg::Vec4( refract, refract*refract, 0.0f, 0.0f ) );
319    stateset->setAttributeAndModes( vp, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
320
321    // ---------------------------------------------------
322    // fragment = refraction*(1-fresnel) + reflection*fresnel
323    // T0 = texture unit 0, refraction map
324    // T1 = texture unit 1, reflection map
325    // C.rgb = primary color, water color
326    // C.a   = primary color, fresnel factor
327    // Cp    = result from previous texture environment
328    // ---------------------------------------------------
329
330    // REPLACE function: Arg0
331    // = T0
332    osg::TexEnvCombine *te0 = new osg::TexEnvCombine;   
333    te0->setCombine_RGB(osg::TexEnvCombine::REPLACE);
334    te0->setSource0_RGB(osg::TexEnvCombine::TEXTURE0);
335    te0->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
336   
337    // INTERPOLATE function: Arg0 * (Arg2) + Arg1 * (1-Arg2)
338    // = T1 * C0.a + Cp * (1-C0.a)
339    osg::TexEnvCombine *te1 = new osg::TexEnvCombine;   
340
341    // rgb = Cp + Ct
342    te1->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE);
343    te1->setSource0_RGB(osg::TexEnvCombine::TEXTURE1);
344    te1->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR);
345    te1->setSource1_RGB(osg::TexEnvCombine::PREVIOUS);
346    te1->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR);
347    te1->setSource2_RGB(osg::TexEnvCombine::PRIMARY_COLOR);
348    te1->setOperand2_RGB(osg::TexEnvCombine::SRC_COLOR);
349
350    stateset->setTextureAttributeAndModes(0, te0, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
351    stateset->setTextureAttributeAndModes(1, te1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
352
353    osg::Group* group = new osg::Group;
354    group->addChild(node);
355    group->setCullCallback(new TexMatCallback(*texMat));
356    group->setStateSet( stateset );
357   
358    return group;
359}
360
361
362int main(int argc, char *argv[])
363{
364    // use an ArgumentParser object to manage the program arguments.
365    osg::ArgumentParser arguments(&argc,argv);
366
367    // construct the viewer.
368    osgViewer::Viewer viewer;
369
370    osg::Group* rootnode = new osg::Group;
371
372    rootnode->addChild(createSkyBox());
373
374    // load the nodes from the commandline arguments.
375    osg::Node* model = osgDB::readNodeFiles(arguments);
376    if (!model)
377    {
378        const float radius = 1.0f;
379        osg::Geode* geode = new osg::Geode;
380        geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f,0.0f,0.0f),radius)));
381        model = geode;
382    }
383
384    // run optimization over the scene graph
385    osgUtil::Optimizer optimzer;
386    optimzer.optimize(model);
387
388    // create normals.   
389    osgUtil::SmoothingVisitor smoother;
390    model->accept(smoother);
391
392    rootnode->addChild( addRefractStateSet(model) );
393
394    // add a viewport to the viewer and attach the scene graph.
395    viewer.setSceneData(rootnode);
396   
397    // create the windows and run the threads.
398    viewer.realize();
399
400    // now check to see if vertex program is supported.
401    osgViewer::Viewer::Windows windows;
402    viewer.getWindows(windows);
403    for(osgViewer::Viewer::Windows::iterator itr = windows.begin();
404        itr != windows.end();
405        ++itr)
406    {
407        unsigned int contextID = (*itr)->getState()->getContextID();
408        osg::VertexProgram::Extensions* vpExt = osg::VertexProgram::getExtensions(contextID,false);
409        if (vpExt)
410        {
411            if (!vpExt->isVertexProgramSupported())
412            {
413                std::cout<<"Warning: ARB_vertex_program not supported by OpenGL drivers, unable to run application."<<std::endl;
414                return 1;
415            }
416        }
417    }
418
419    return viewer.run();
420}
Note: See TracBrowser for help on using the browser.