#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace osg; // This example is based on the sample code in the // ARB_uniform_buffer_object extension specification. GLfloat colors1[] = { // block 0.45,0.45,1,1, 0.45,0.45,1,1, 0.75,0.75,0.75,1, 0.0,0.0,1.0,1, 0.0,1.0,0.0,1 }; GLfloat colors2[] = { // block 0.45,0.45,1,1, 0.45,0.45,1,1, 0.75,0.75,0.75,1, 1.0,0.0,0.0,1, 0.0,1.0,0.0,1, }; char vertexShaderSource[] = "// Vertex shader for Gooch shading\n" "// Author: Randi Rost\n" "// Copyright (c) 2002-2006 3Dlabs Inc. Ltd.\n" "// See 3Dlabs-License.txt for license information\n" "vec3 LightPosition = vec3(0.0, 10.0, 4.0); \n" "varying float NdotL;\n" "varying vec3 ReflectVec;\n" "varying vec3 ViewVec;\n" "void main(void)\n" "{\n" "vec3 ecPos = vec3 (gl_ModelViewMatrix * gl_Vertex);\n" "vec3 tnorm = normalize(gl_NormalMatrix * gl_Normal);\n" "vec3 lightVec = normalize(LightPosition - ecPos);\n" "ReflectVec = normalize(reflect(-lightVec, tnorm));\n" "ViewVec = normalize(-ecPos);\n" "NdotL = (dot(lightVec, tnorm) + 1.0) * 0.5;\n" "gl_Position = ftransform();\n" "}\n"; char fragmentShaderSource[] = "// Fragment shader for Gooch shading, adapted for ARB_uniform_buffer_object\n" "#extension GL_ARB_uniform_buffer_object : enable\n" "layout(std140) uniform colors0\n" "{\n" "float DiffuseCool;\n" "float DiffuseWarm;\n" "vec3 SurfaceColor;\n" "vec3 WarmColor;\n" "vec3 CoolColor;\n" "};\n" "varying float NdotL;\n" "varying vec3 ReflectVec;\n" "varying vec3 ViewVec;\n" "void main (void)\n" "{\n" "vec3 kcool = min(CoolColor + DiffuseCool * SurfaceColor, 1.0);\n" "vec3 kwarm = min(WarmColor + DiffuseWarm * SurfaceColor, 1.0); \n" "vec3 kfinal = mix(kcool, kwarm, NdotL);\n" "vec3 nreflect = normalize(ReflectVec);\n" "vec3 nview = normalize(ViewVec);\n" "float spec = max(dot(nreflect, nview), 0.0);\n" "spec = pow(spec, 32.0);\n" "gl_FragColor = vec4 (min(kfinal + spec, 1.0), 1.0);\n" "}\n"; // Callback for animating the WarmColor class UniformBufferCallback : public StateAttributeCallback { public: void operator() (StateAttribute* attr, NodeVisitor* nv) { UniformBufferBinding* ubb = static_cast(attr); UniformBufferObject* ubo = static_cast(ubb->getBufferObject()); FloatArray* array = static_cast(ubo->getBufferData(0)); double time = nv->getFrameStamp()->getSimulationTime(); double frac = fmod(time, 1.0); Vec4f warmColor = (Vec4f(0.0, 0.0, 1.0 ,1) * frac + Vec4f(1.0, 0.0, 0.0, 1) * (1 - frac)); // Since we're using the std140 layout, we know where the // warmColor variable is located in the buffer. for (int i = 0; i < 4; ++i) (*array)[12 + i] = warmColor[i]; array->dirty(); } }; int main(int argc, char** argv) { osg::ArgumentParser arguments(&argc,argv); osgViewer::Viewer viewer(arguments); if (arguments.argc() <= 1) { cerr << "Need a scene.\n"; return 1; } osg::ref_ptr loadedModel = osgDB::readRefNodeFiles(arguments); if (!loadedModel) { cerr << "couldn't load " << argv[1] << "\n"; return 1; } osgUtil::Optimizer optimizer; optimizer.optimize(loadedModel.get()); const BoundingSphere bound = loadedModel->getBound(); const float displacement = 2.25 * bound.radius(); Group* scene = new Group; StateSet* rootSS = scene->getOrCreateStateSet(); Shader* vertexShader = new Shader(Shader::VERTEX); vertexShader->setShaderSource(vertexShaderSource); Shader* fragmentShader = new Shader(Shader::FRAGMENT); fragmentShader->setShaderSource(fragmentShaderSource); Program* prog = new Program; prog->addShader(vertexShader); prog->addShader(fragmentShader); prog->addBindUniformBlock("colors0", 0); rootSS->setAttributeAndModes(prog, StateAttribute::ON); // Place 3 instances of the loaded model with different uniform // blocks for each. // // The blocksize is known because of the std140 format. const unsigned blockSize = 20 * sizeof(GLfloat); ref_ptr colorArray = new FloatArray(&colors1[0], &colors1[sizeof(colors1) / sizeof(GLfloat)]); ref_ptr ubo = new UniformBufferObject; colorArray->setBufferObject(ubo.get()); Group* group1 = new Group; StateSet* ss1 = group1->getOrCreateStateSet(); group1->addChild(loadedModel.get()); scene->addChild(group1); ref_ptr ubb1 = new UniformBufferBinding(0, ubo.get(), 0, blockSize); ss1->setAttributeAndModes(ubb1.get(), StateAttribute::ON); ref_ptr colorArray2 = new FloatArray(&colors2[0], &colors2[sizeof(colors2) / sizeof(GLfloat)]); ref_ptr ubo2 = new UniformBufferObject; colorArray2->setBufferObject(ubo2.get()); MatrixTransform* group2 = new MatrixTransform; Matrix mat2 = Matrix::translate(-displacement, 0.0, 0.0); group2->setMatrix(mat2); StateSet* ss2 = group2->getOrCreateStateSet(); group2->addChild(loadedModel.get()); scene->addChild(group2); ref_ptr ubb2 = new UniformBufferBinding(0, ubo2.get(), 0, blockSize); ss2->setAttributeAndModes(ubb2.get(), StateAttribute::ON); ref_ptr colorArray3 = new FloatArray(&colors2[0], &colors2[sizeof(colors2) / sizeof(GLfloat)]); ref_ptr ubo3 = new UniformBufferObject; colorArray3->setBufferObject(ubo3.get()); MatrixTransform* group3 = new MatrixTransform; Matrix mat3 = Matrix::translate(displacement, 0.0, 0.0); group3->setMatrix(mat3); StateSet* ss3 = group3->getOrCreateStateSet(); group3->addChild(loadedModel.get()); scene->addChild(group3); ref_ptr ubb3 = new UniformBufferBinding(0, ubo3.get(), 0, blockSize); ubb3->setUpdateCallback(new UniformBufferCallback); ubb3->setDataVariance(Object::DYNAMIC); ss3->setAttributeAndModes(ubb3.get(), StateAttribute::ON); viewer.setSceneData(scene); viewer.realize(); return viewer.run(); }