Hi Robert,

There is no way to increase or decrease the tessellation evenly with
one key in the tessellation shader example. I expected that pressing
plus would increase both the inner and outer tessellation at the same
time. Instead I have to press up arrow and then right arrow. There is
no way to decrease the tessellation evenly either. I have to press
down arrow and then left arrow.

I have changed the code so that the plus key increases both the inner
and outer tessellation. The minus key decrease both the inner and
outer tessellation. You can still use the arrow keys to control inner
and outer tessellation separately.

I have tested it on Windows 8.1. The arrow keys still work the same way.

Base version is 14689.

Thank you,
Michael Mc Donnell
/* 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));

    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), osgGA::GUIEventHandler(){
            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);
        _tessInnerU->set(_tessInner);
    }

    void increaseOuterTesselation() {
        _tessOuterU->set(++_tessOuter);
    }

    void decreaseOuterTesselation() {
        _tessOuter = std::max(1.0f, --_tessOuter);
        _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

Reply via email to