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