1

Currently I have problems by handling uniforms on GLSL shaders. If I have only one object in the scene, the uniform works as I expect. However, for multiple objects, the uniform is not set per object, in other words, the last uniform is used to represent all scene objects.

How can I handle with this problem? Follows my C++ code:

void addSimpleObject(osg::ref_ptr<osg::Group> root, osg::Vec3 position, float radius, float myUniform) {

    osg::ref_ptr<osg::Geode> geode = new osg::Geode();
    geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(position, radius)));
    root->addChild(geode);
    root->getChild(0)->asGeode()->addDrawable(geode->getDrawable(0));

    osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
    stateset->addUniform(new osg::Uniform("myUniform", myUniform));
    root->setStateSet(stateset);
}


osg::ref_ptr<osg::Group> root = new osg::Group();
addSimpleObject(root, osg::Vec3(-3.0,  2.5, -10), 2, 0.5);
addSimpleObject(root, osg::Vec3( 3.0,  2.5, -10), 2, 1.5);
addSimpleObject(root, osg::Vec3( 0.0, -2.5, -10), 2, 1.0);

The vertex shader:

#version 130

out vec3 pos;
out vec3 normal;

void main() {
    pos = (gl_ModelViewMatrix * gl_Vertex).xyz;
    normal = gl_NormalMatrix * gl_Normal;
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
}

And the fragment shader:

#version 130

in vec3 pos;
in vec3 normal;

uniform float myUniform;

void main() {
    vec3 normNormal;

    normNormal = normalize(normal);

    if (myUniform > 0)
        normNormal = min(normNormal * myUniform, 1.0);

    ...
}

image output

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • 1
    A uniform is bound to a shader program not to an "object". If use the same program for all objects yoa have to set the uniform before drawing the object. – Rabbid76 Jul 02 '17 at 11:45
  • Hi @Rabbid76, thanks for your answer. Could you give me an example? How can I fix my program to address your suggestion? – Rômulo Cerqueira Jul 02 '17 at 13:16

1 Answers1

4

A uniform is bound to a shader program not to an "object". If use the same program for all objects you have to set the uniform before drawing the object.

You bound the osg::StateSet to the root node of the scene graph. If the value of the uniform variable changes for each drawable you have to add a separated osg::StateSet to each osg::Drawable node.

Adapt your method addSimpleObject like this:

void addSimpleObject(osg::ref_ptr<osg::Group> root, osg::Vec3 position, float radius, float myUniform) {

    // create the drawable 
    osg::ref_ptr<osg::Drawable> drawable = new osg::ShapeDrawable(new osg::Sphere(position, radius))

    // crate the stateset and add the uniform
    osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet();
    stateset->addUniform(new osg::Uniform("myUniform", myUniform));

    // add the stateset tor the drawable
    drawable->setStateSet(stateset);

    if (root->getNumChildren() == 0) {
        osg::ref_ptr<osg::Geode> geode = new osg::Geode();
        root->addChild(geode);
    }
    root->getChild(0)->asGeode()->addDrawable(drawable);
} 
Rabbid76
  • 202,892
  • 27
  • 131
  • 174