1 #include <iostream>
2 
3 #include <osg/Array>
4 #include <osg/BoundingSphere>
5 #include <osg/BufferIndexBinding>
6 #include <osg/BufferObject>
7 #include <osg/Group>
8 #include <osg/Math>
9 #include <osg/MatrixTransform>
10 #include <osg/Program>
11 #include <osg/Shader>
12 
13 #include <osgDB/ReadFile>
14 #include <osgDB/WriteFile>
15 #include <osgUtil/Optimizer>
16 
17 #include <osgViewer/Viewer>
18 #include <osgViewer/ViewerEventHandlers>
19 
20 using namespace std;
21 using namespace osg;
22 
23 // This example is based on the sample code in the
24 // ARB_uniform_buffer_object extension specification.
25 
26 GLfloat colors1[] = {
27     // block
28     0.45,0.45,1,1,
29     0.45,0.45,1,1,
30     0.75,0.75,0.75,1,
31     0.0,0.0,1.0,1,
32     0.0,1.0,0.0,1
33 };
34 GLfloat colors2[] = {
35     // block
36     0.45,0.45,1,1,
37     0.45,0.45,1,1,
38     0.75,0.75,0.75,1,
39     1.0,0.0,0.0,1,
40     0.0,1.0,0.0,1,
41 };
42 
43 char vertexShaderSource[] =
44     "// Vertex shader for Gooch shading\n"
45     "// Author: Randi Rost\n"
46     "// Copyright (c) 2002-2006 3Dlabs Inc. Ltd.\n"
47     "// See 3Dlabs-License.txt for license information\n"
48 
49     "vec3 LightPosition = vec3(0.0, 10.0, 4.0); \n"
50 
51     "varying float NdotL;\n"
52     "varying vec3  ReflectVec;\n"
53     "varying vec3  ViewVec;\n"
54 
55     "void main(void)\n"
56     "{\n"
57         "vec3 ecPos      = vec3 (gl_ModelViewMatrix * gl_Vertex);\n"
58         "vec3 tnorm      = normalize(gl_NormalMatrix * gl_Normal);\n"
59         "vec3 lightVec   = normalize(LightPosition - ecPos);\n"
60         "ReflectVec      = normalize(reflect(-lightVec, tnorm));\n"
61         "ViewVec         = normalize(-ecPos);\n"
62         "NdotL           = (dot(lightVec, tnorm) + 1.0) * 0.5;\n"
63         "gl_Position     = ftransform();\n"
64     "}\n";
65 
66 char fragmentShaderSource[] =
67     "// Fragment shader for Gooch shading, adapted for ARB_uniform_buffer_object\n"
68 
69     "#extension GL_ARB_uniform_buffer_object : enable\n"
70 
71     "layout(std140) uniform colors0\n"
72     "{\n"
73         "float DiffuseCool;\n"
74         "float DiffuseWarm;\n"
75         "vec3  SurfaceColor;\n"
76         "vec3  WarmColor;\n"
77         "vec3  CoolColor;\n"
78     "};\n"
79 
80     "varying float NdotL;\n"
81     "varying vec3  ReflectVec;\n"
82     "varying vec3  ViewVec;\n"
83 
84     "void main (void)\n"
85     "{\n"
86         "vec3 kcool    = min(CoolColor + DiffuseCool * SurfaceColor, 1.0);\n"
87         "vec3 kwarm    = min(WarmColor + DiffuseWarm * SurfaceColor, 1.0); \n"
88         "vec3 kfinal   = mix(kcool, kwarm, NdotL);\n"
89 
90         "vec3 nreflect = normalize(ReflectVec);\n"
91         "vec3 nview    = normalize(ViewVec);\n"
92 
93         "float spec    = max(dot(nreflect, nview), 0.0);\n"
94         "spec          = pow(spec, 32.0);\n"
95 
96         "gl_FragColor = vec4 (min(kfinal + spec, 1.0), 1.0);\n"
97     "}\n";
98 
99 // Callback for animating the WarmColor
100 
101 class UniformBufferCallback : public StateAttributeCallback
102 {
103 public:
operator ()(StateAttribute * attr,NodeVisitor * nv)104     void operator() (StateAttribute* attr, NodeVisitor* nv)
105     {
106         UniformBufferBinding* ubb = static_cast<UniformBufferBinding*>(attr);
107         UniformBufferObject* ubo
108             = static_cast<UniformBufferObject*>(ubb->getBufferObject());
109         FloatArray* array = static_cast<FloatArray*>(ubo->getBufferData(0));
110         double time = nv->getFrameStamp()->getSimulationTime();
111         double frac = fmod(time, 1.0);
112         Vec4f warmColor = (Vec4f(0.0, 0.0, 1.0 ,1) * frac
113                            +  Vec4f(1.0, 0.0, 0.0, 1) * (1 - frac));
114         // Since we're using the std140 layout, we know where the
115         // warmColor variable is located in the buffer.
116         for (int i = 0; i < 4; ++i)
117             (*array)[12 + i] = warmColor[i];
118         array->dirty();
119     }
120 };
121 
main(int argc,char ** argv)122 int main(int argc, char** argv)
123 {
124     osg::ArgumentParser arguments(&argc,argv);
125     osgViewer::Viewer viewer(arguments);
126 
127     if (arguments.argc() <= 1) {
128         cerr << "Need a scene.\n";
129         return 1;
130     }
131 
132     osg::ref_ptr<osg::Node> loadedModel = osgDB::readRefNodeFiles(arguments);
133     if (!loadedModel) {
134         cerr << "couldn't load " << argv[1] << "\n";
135         return 1;
136     }
137     osgUtil::Optimizer optimizer;
138     optimizer.optimize(loadedModel.get());
139     const BoundingSphere bound = loadedModel->getBound();
140     const float displacement = 2.25 * bound.radius();
141     Group* scene = new Group;
142     StateSet* rootSS = scene->getOrCreateStateSet();
143 
144     Shader* vertexShader = new Shader(Shader::VERTEX);
145     vertexShader->setShaderSource(vertexShaderSource);
146     Shader* fragmentShader = new Shader(Shader::FRAGMENT);
147     fragmentShader->setShaderSource(fragmentShaderSource);
148     Program* prog = new Program;
149     prog->addShader(vertexShader);
150     prog->addShader(fragmentShader);
151     prog->addBindUniformBlock("colors0", 0);
152     rootSS->setAttributeAndModes(prog, StateAttribute::ON);
153     // Place 3 instances of the loaded model with different uniform
154     // blocks for each.
155     //
156     // The blocksize is known because of the std140 format.
157     const unsigned blockSize = 20 * sizeof(GLfloat);
158     ref_ptr<FloatArray> colorArray
159         = new FloatArray(&colors1[0],
160                          &colors1[sizeof(colors1) / sizeof(GLfloat)]);
161     ref_ptr<UniformBufferObject> ubo = new UniformBufferObject;
162     colorArray->setBufferObject(ubo.get());
163     Group* group1 = new Group;
164     StateSet* ss1 = group1->getOrCreateStateSet();
165     group1->addChild(loadedModel.get());
166     scene->addChild(group1);
167     ref_ptr<UniformBufferBinding> ubb1
168         = new UniformBufferBinding(0, ubo.get(), 0, blockSize);
169     ss1->setAttributeAndModes(ubb1.get(), StateAttribute::ON);
170 
171     ref_ptr<FloatArray> colorArray2
172         = new FloatArray(&colors2[0],
173                          &colors2[sizeof(colors2) / sizeof(GLfloat)]);
174     ref_ptr<UniformBufferObject> ubo2 = new UniformBufferObject;
175     colorArray2->setBufferObject(ubo2.get());
176     MatrixTransform* group2 = new MatrixTransform;
177     Matrix mat2 = Matrix::translate(-displacement, 0.0, 0.0);
178     group2->setMatrix(mat2);
179     StateSet* ss2 = group2->getOrCreateStateSet();
180     group2->addChild(loadedModel.get());
181     scene->addChild(group2);
182     ref_ptr<UniformBufferBinding> ubb2
183         = new UniformBufferBinding(0, ubo2.get(), 0, blockSize);
184     ss2->setAttributeAndModes(ubb2.get(), StateAttribute::ON);
185 
186     ref_ptr<FloatArray> colorArray3
187         = new FloatArray(&colors2[0],
188                          &colors2[sizeof(colors2) / sizeof(GLfloat)]);
189     ref_ptr<UniformBufferObject> ubo3 = new UniformBufferObject;
190     colorArray3->setBufferObject(ubo3.get());
191     MatrixTransform* group3 = new MatrixTransform;
192     Matrix mat3 = Matrix::translate(displacement, 0.0, 0.0);
193     group3->setMatrix(mat3);
194     StateSet* ss3 = group3->getOrCreateStateSet();
195     group3->addChild(loadedModel.get());
196     scene->addChild(group3);
197     ref_ptr<UniformBufferBinding> ubb3
198         = new UniformBufferBinding(0, ubo3.get(), 0, blockSize);
199     ubb3->setUpdateCallback(new UniformBufferCallback);
200     ubb3->setDataVariance(Object::DYNAMIC);
201     ss3->setAttributeAndModes(ubb3.get(), StateAttribute::ON);
202 
203     viewer.setSceneData(scene);
204     viewer.realize();
205     return viewer.run();
206 }
207