Hi Robert, The tessellation shader example has a small bug.The middle of the geometry is clipped as soon as it is tessellated. The clipping is probably caused by rounding errors because it is only in one spot. The clipping disappears when the camera is moved, and reappears when it is moved back. Expanding the the bounding box fixed the clipping bug.
I have attached the fix as a patch file and the whole file itself. Written against svn revision 14745. Thank you, Michael Mc Donnell
Fixed-clipping-bug-in-osgtessellationshaders-example.patch
Description: Binary data
/* A demonstration of Tessellation Shaders in OpenScenegraph.
*
* Instructions:
* Press plus to increase tesselation and minus to decrease it.
* Press right arrow to increase inner tesselation and left arrow to decrease it.
* Press up arrow to increase outer tesselation and down arrow to decrease it.
*
* Original code by Philip Rideout
* Adapted to OpenScenegraph by John Kaniarz
* Additional work by Michael Mc Donnell
*/
#include <osg/Program>
#include <osg/PatchParameter>
#include <osg/ShapeDrawable>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgGA/TrackballManipulator>
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<osg::Geode> 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;i<VertexCount;i+=3){
vertices->push_back(osg::Vec3(Verts[i],Verts[i+1],Verts[i+2]));
}
geometry->setVertexArray(vertices);
geometry->addPrimitiveSet(new osg::DrawElementsUInt(osg::PrimitiveSet::PATCHES,IndexCount,Faces));
// Expand the bounding box, otherwise the geometry is clipped in front when tessellating.
osg::BoundingBox bbox(osg::Vec3(-0.9f, -0.9f, -1.0f), osg::Vec3(0.9f, 0.9f, 1.0f));
geometry->setInitialBound(bbox);
geode->addDrawable(geometry);
return geode;
}
osg::ref_ptr<osg::Program> 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);
return program;
}
class KeyboardEventHandler : public osgGA::GUIEventHandler
{
public:
KeyboardEventHandler(osg::ref_ptr<osg::Uniform> tessInnerU, osg::ref_ptr<osg::Uniform> tessOuterU):
_tessInnerU(tessInnerU),
_tessOuterU(tessOuterU)
{
tessInnerU->get(_tessInner);
tessOuterU->get(_tessOuter);
}
virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& gaa)
{
if(ea.getEventType()==osgGA::GUIEventAdapter::KEYDOWN){
switch (ea.getKey()){
case osgGA::GUIEventAdapter::KEY_Up:
increaseOuterTesselation();
return true;
case osgGA::GUIEventAdapter::KEY_Down:
decreaseOuterTesselation();
return true;
case osgGA::GUIEventAdapter::KEY_Left:
decreaseInnerTesselation();
return true;
case osgGA::GUIEventAdapter::KEY_Right:
increaseInnerTesselation();
return true;
case osgGA::GUIEventAdapter::KEY_Plus:
case osgGA::GUIEventAdapter::KEY_KP_Add:
increaseInnerTesselation();
increaseOuterTesselation();
return true;
case osgGA::GUIEventAdapter::KEY_Minus:
case osgGA::GUIEventAdapter::KEY_KP_Subtract:
decreaseInnerTesselation();
decreaseOuterTesselation();
return true;
}
}
return osgGA::GUIEventHandler::handle(ea, gaa);
}
private:
osg::ref_ptr<osg::Uniform> _tessInnerU;
osg::ref_ptr<osg::Uniform> _tessOuterU;
float _tessInner;
float _tessOuter;
void increaseInnerTesselation()
{
_tessInnerU->set(++_tessInner);
}
void decreaseInnerTesselation()
{
_tessInner = std::max(1.0f, _tessInner-1.0f);
_tessInnerU->set(_tessInner);
}
void increaseOuterTesselation()
{
_tessOuterU->set(++_tessOuter);
}
void decreaseOuterTesselation()
{
_tessOuter = std::max(1.0f, _tessOuter-1.0f);
_tessOuterU->set(_tessOuter);
}
};
int main(int argc, char* argv[])
{
osgViewer::Viewer viewer;
viewer.setUpViewInWindow(100,100,800,600);
osg::ref_ptr<osg::Program> program = createProgram();
osg::ref_ptr<osg::Geode> geode = CreateIcosahedron(program.get());
osg::ref_ptr<osg::Uniform> tessInnerU = new osg::Uniform("TessLevelInner", 1.0f);
osg::ref_ptr<osg::Uniform> tessOuterU = new osg::Uniform("TessLevelOuter", 1.0f);
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(new osg::PatchParameter(3));
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(tessInnerU, tessOuterU));
viewer.setSceneData(geode.get());
return viewer.run();
}
_______________________________________________ osg-submissions mailing list [email protected] http://lists.openscenegraph.org/listinfo.cgi/osg-submissions-openscenegraph.org
