From b0c510ab0849dea0b2ad0694544d5e0e70b3e17f Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 20 Apr 2012 09:38:51 +0000 Subject: [PATCH] From John Kaniarz, "Here is an example of using tessellation shaders in osg. With permission from the author, I adapted it from this tutorial: http://prideout.net/blog/?p=48" --- examples/CMakeLists.txt | 1 + .../osgtessellationshaders/CMakeLists.txt | 2 + .../osgtessellationshaders.cpp | 247 ++++++++++++++++++ 3 files changed, 250 insertions(+) create mode 100644 examples/osgtessellationshaders/CMakeLists.txt create mode 100644 examples/osgtessellationshaders/osgtessellationshaders.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 59e6a22f4..170e24fd8 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -176,6 +176,7 @@ IF(DYNAMIC_OPENSCENEGRAPH) ADD_SUBDIRECTORY(osgphotoalbum) ADD_SUBDIRECTORY(osgtessellate) + ADD_SUBDIRECTORY(osgtessellationshaders) ADD_SUBDIRECTORY(osgpdf) diff --git a/examples/osgtessellationshaders/CMakeLists.txt b/examples/osgtessellationshaders/CMakeLists.txt new file mode 100644 index 000000000..4ad3c12a6 --- /dev/null +++ b/examples/osgtessellationshaders/CMakeLists.txt @@ -0,0 +1,2 @@ +SET(TARGET_SRC osgtessellationshaders.cpp ) +SETUP_EXAMPLE(osgtessellationshaders) diff --git a/examples/osgtessellationshaders/osgtessellationshaders.cpp b/examples/osgtessellationshaders/osgtessellationshaders.cpp new file mode 100644 index 000000000..fae775ac5 --- /dev/null +++ b/examples/osgtessellationshaders/osgtessellationshaders.cpp @@ -0,0 +1,247 @@ +/* A demonstration of Tessellation Shaders in OpenScenegraph. + * Original code by Philip Rideout + * Adapted to OpenScenegraph by John Kaniarz + */ + +#include +#include +#include +#include +#include + +static const char* vertSource = { +"#version 400\n" +"in vec4 osg_Vertex;\n" +"out vec3 vPosition;\n" +"void main(){\n" +" vPosition = osg_Vertex.xyz;\n" +"}\n" +}; +static const char* tessControlSource = { +"#version 400\n" +"layout(vertices = 3) out;\n" +"in vec3 vPosition[];\n" +"out vec3 tcPosition[];\n" +"uniform float TessLevelInner;\n" +"uniform float TessLevelOuter;\n" +"#define ID gl_InvocationID\n" +"void main(){\n" +" tcPosition[ID] = vPosition[ID];\n" +" if (ID == 0) {\n" +" gl_TessLevelInner[0] = TessLevelInner;\n" +" gl_TessLevelOuter[0] = TessLevelOuter;\n" +" gl_TessLevelOuter[1] = TessLevelOuter;\n" +" gl_TessLevelOuter[2] = TessLevelOuter;\n" +" }\n" +"}\n" +}; +static const char* tessEvalSource = { +"#version 400\n" +"layout(triangles, equal_spacing, cw) in;\n" +"in vec3 tcPosition[];\n" +"out vec3 tePosition;\n" +"out vec3 tePatchDistance;\n" +"uniform mat4 osg_ProjectionMatrix;\n" +"uniform mat4 osg_ModelViewMatrix;\n" +"void main(){\n" +" vec3 p0 = gl_TessCoord.x * tcPosition[0];\n" +" vec3 p1 = gl_TessCoord.y * tcPosition[1];\n" +" vec3 p2 = gl_TessCoord.z * tcPosition[2];\n" +" tePatchDistance = gl_TessCoord;\n" +" tePosition = normalize(p0 + p1 + p2);\n" +" gl_Position = osg_ProjectionMatrix * osg_ModelViewMatrix * vec4(tePosition, 1);\n" +"}\n" +}; +static const char* geomSource = { +"#version 400\n" +"uniform mat4 osg_ModelViewMatrix;\n" +"uniform mat3 osg_NormalMatrix;\n" +"layout(triangles) in;\n" +"layout(triangle_strip, max_vertices = 3) out;\n" +"in vec3 tePosition[3];\n" +"in vec3 tePatchDistance[3];\n" +"out vec3 gFacetNormal;\n" +"out vec3 gPatchDistance;\n" +"out vec3 gTriDistance;\n" +"out vec4 gColor;\n" +"void main(){\n" +" vec3 A = tePosition[2] - tePosition[0];\n" +" vec3 B = tePosition[1] - tePosition[0];\n" +" gFacetNormal = osg_NormalMatrix * normalize(cross(A, B));\n" +" gPatchDistance = tePatchDistance[0];\n" +" gTriDistance = vec3(1, 0, 0);\n" +" gColor = osg_ModelViewMatrix[0];\n" +" gl_Position = gl_in[0].gl_Position; EmitVertex();\n" +" gPatchDistance = tePatchDistance[1];\n" +" gTriDistance = vec3(0, 1, 0);\n" +" gColor = osg_ModelViewMatrix[1];\n" +" gl_Position = gl_in[1].gl_Position; EmitVertex();\n" +" gPatchDistance = tePatchDistance[2];\n" +" gTriDistance = vec3(0, 0, 1);\n" +" gColor = osg_ModelViewMatrix[2];\n" +" gl_Position = gl_in[2].gl_Position; EmitVertex();\n" +" EndPrimitive();\n" +"}\n" +}; +static const char* fragSource = { +"#version 400\n" +"out vec4 FragColor;\n" +"in vec3 gFacetNormal;\n" +"in vec3 gTriDistance;\n" +"in vec3 gPatchDistance;\n" +"in vec4 gColor;\n" +"in float gPrimitive;\n" +"uniform vec3 LightPosition;\n" +"uniform vec3 DiffuseMaterial;\n" +"uniform vec3 AmbientMaterial;\n" +"float amplify(float d, float scale, float offset){\n" +" d = scale * d + offset;\n" +" d = clamp(d, 0, 1);\n" +" d = 1 - exp2(-2*d*d);\n" +" return d;\n" +"}\n" +"void main(){\n" +" vec3 N = normalize(gFacetNormal);\n" +" vec3 L = LightPosition;\n" +" float df = abs(dot(N, L));\n" +" vec3 color = AmbientMaterial + df * DiffuseMaterial;\n" +" float d1 = min(min(gTriDistance.x, gTriDistance.y), gTriDistance.z);\n" +" float d2 = min(min(gPatchDistance.x, gPatchDistance.y), gPatchDistance.z);\n" +" color = amplify(d1, 40, -0.5) * amplify(d2, 60, -0.5) * color;\n" +" FragColor = vec4(color, 1.0);\n" +"}\n" +}; + +osg::ref_ptr CreateIcosahedron(osg::Program *program){ + osg::Geode *geode=new osg::Geode(); + osg::Geometry *geometry = new osg::Geometry(); + const unsigned int Faces[] = { + 2, 1, 0, + 3, 2, 0, + 4, 3, 0, + 5, 4, 0, + 1, 5, 0, + + 11, 6, 7, + 11, 7, 8, + 11, 8, 9, + 11, 9, 10, + 11, 10, 6, + + 1, 2, 6, + 2, 3, 7, + 3, 4, 8, + 4, 5, 9, + 5, 1, 10, + + 2, 7, 6, + 3, 8, 7, + 4, 9, 8, + 5, 10, 9, + 1, 6, 10 }; + int IndexCount = sizeof(Faces) / sizeof(Faces[0]); + const float Verts[] = { + 0.000f, 0.000f, 1.000f, + 0.894f, 0.000f, 0.447f, + 0.276f, 0.851f, 0.447f, + -0.724f, 0.526f, 0.447f, + -0.724f, -0.526f, 0.447f, + 0.276f, -0.851f, 0.447f, + 0.724f, 0.526f, -0.447f, + -0.276f, 0.851f, -0.447f, + -0.894f, 0.000f, -0.447f, + -0.276f, -0.851f, -0.447f, + 0.724f, -0.526f, -0.447f, + 0.000f, 0.000f, -1.000f }; + + int VertexCount = sizeof(Verts)/sizeof(float); + osg::Vec3Array* vertices = new osg::Vec3Array(); + for(int i=0;ipush_back(osg::Vec3(Verts[i],Verts[i+1],Verts[i+2])); + } + geometry->setVertexArray(vertices); + geometry->addPrimitiveSet(new osg::DrawElementsUInt(osg::PrimitiveSet::PATCHES,IndexCount,Faces)); + + geode->addDrawable(geometry); + return geode; +} +osg::ref_ptr createProgram(){ + osg::Program *program = new osg::Program(); + program->addShader(new osg::Shader(osg::Shader::VERTEX,vertSource)); + program->addShader(new osg::Shader(osg::Shader::TESSCONTROL,tessControlSource)); + program->addShader(new osg::Shader(osg::Shader::TESSEVALUATION,tessEvalSource)); + program->addShader(new osg::Shader(osg::Shader::GEOMETRY,geomSource)); + program->addShader(new osg::Shader(osg::Shader::FRAGMENT,fragSource)); + program->setParameter(GL_GEOMETRY_VERTICES_OUT_EXT, 3); + program->setParameter(GL_GEOMETRY_INPUT_TYPE_EXT, GL_TRIANGLES); + program->setParameter(GL_GEOMETRY_OUTPUT_TYPE_EXT, GL_TRIANGLE_STRIP); + program->setParameter(GL_PATCH_VERTICES,3); + return program; +} + +float tessInner=1.0f; +float tessOuter=1.0f; +osg::ref_ptr tessInnerU = new osg::Uniform("TessLevelInner",tessInner); +osg::ref_ptr tessOuterU = new osg::Uniform("TessLevelOuter",tessOuter); + +class KeyboardEventHandler : public osgGA::GUIEventHandler { +public: + KeyboardEventHandler():osgGA::GUIEventHandler(){} + virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& gaa){ + if(ea.getEventType()==osgGA::GUIEventAdapter::KEYDOWN){ + switch (ea.getKey()){ + case osgGA::GUIEventAdapter::KEY_Up: + tessOuter++; + tessOuterU->set(tessOuter); + return true; + case osgGA::GUIEventAdapter::KEY_Down: + tessOuter--; + tessOuter=std::max(1.0f,tessOuter); + tessOuterU->set(tessOuter); + return true; + case osgGA::GUIEventAdapter::KEY_Left: + tessInner--; + tessInner=std::max(1.0f,tessInner); + tessInnerU->set(tessInner); + return true; + case osgGA::GUIEventAdapter::KEY_Right: + tessInner++; + tessInnerU->set(tessInner); + return true; + } + } + return osgGA::GUIEventHandler::handle(ea,gaa); + } +}; +int main(int argc, char* argv[]) +{ + osgViewer::Viewer viewer; + viewer.setUpViewInWindow(100,100,800,600); + osg::ref_ptr program = createProgram(); + osg::ref_ptr geode = CreateIcosahedron(program.get()); + osg::StateSet *state; + state = geode->getOrCreateStateSet(); + state->addUniform(new osg::Uniform("AmbientMaterial",osg::Vec3(0.04f, 0.04f, 0.04f))); + state->addUniform(new osg::Uniform("DiffuseMaterial",osg::Vec3(0.0f, 0.75f, 0.75f))); + state->addUniform(new osg::Uniform("LightPosition",osg::Vec3(0.25f, 0.25f, 1.0f))); + state->addUniform(tessInnerU.get()); + state->addUniform(tessOuterU.get()); + state->setAttribute(program.get()); + + // switch on the uniforms that track the modelview and projection matrices + osgViewer::Viewer::Windows windows; + viewer.getWindows(windows); + for(osgViewer::Viewer::Windows::iterator itr = windows.begin(); + itr != windows.end(); + ++itr) + { + osg::State *s=(*itr)->getState(); + s->setUseModelViewAndProjectionUniforms(true); + s->setUseVertexAttributeAliasing(true); + } + + viewer.addEventHandler(new KeyboardEventHandler()); + viewer.setSceneData(geode.get()); + return viewer.run(); +} +