Opengl - instanced attributes

487 views Asked by At

I use oglplus - it's a c++ wrapper for OpenGL.

I have a problem with defining instanced data for my particle renderer - positions work fine but something goes wrong when I want to instance a bunch of ints from the same VBO.

I am going to skip some of the implementation details to not make this problem more complicated. Assume that I bind VAO and VBO before described operations.

I have an array of structs (called "Particle") that I upload like this:

glBufferData(GL_ARRAY_BUFFER, sizeof(Particle) * numInstances, newData, GL_DYNAMIC_DRAW);

Definition of the struct:

struct Particle
{
    float3 position;        
    //some more attributes, 9 floats in total
    //(...)
    int fluidID;        
};

I use a helper function to define the OpenGL attributes like this:

void addInstancedAttrib(const InstancedAttribDescriptor& attribDesc, GLSLProgram& program, int offset=0)
        {
            //binding and some implementation details
            //(...)

            oglplus::VertexArrayAttrib attrib(program, attribDesc.getName().c_str());
            attrib.Pointer(attribDesc.getPerVertVals(), attribDesc.getType(), false, sizeof(Particle), (void*)offset);

            attrib.Divisor(1);
            attrib.Enable();
        }

I add attributes for positions and fluidids like this:

            InstancedAttribDescriptor posDesc(3, "InstanceTranslation", oglplus::DataType::Float);
            this->instancedData.addInstancedAttrib(posDesc, this->program);

            InstancedAttribDescriptor fluidDesc(1, "FluidID", oglplus::DataType::Int);
            this->instancedData.addInstancedAttrib(fluidDesc, this->program, (int)offsetof(Particle,fluidID));

Vertex shader code:

uniform vec3 FluidColors[2];

in vec3 InstanceTranslation;
in vec3 VertexPosition;
in vec3 n;

in int FluidID;

out float lightIntensity;
out vec3 sphereColor;

void main()
{   

    //some typical MVP transformations
    //(...)
    sphereColor = FluidColors[FluidID];
    gl_Position = projection * vertexPosEye;

}

This code as whole produces this output:

opengl-problem

As you can see, the particles are arranged in the way I wanted them to be, which means that "InstanceTranslation" property is setup correctly. The group of the particles to the left have FluidID value of 0 and the ones to the right equal to 1. The second set of particles have proper positions but index improperly into FluidColors array.

What I know:

  • It's not a problem with the way I set up the FluidColors uniform. If I hard-code the color selection in the shader like this:

    sphereColor = FluidID == 0? FluidColors[0] : FluidColors1;

I get:

enter image description here

  • OpenGL returns GL_NO_ERROR from glGetError so there's no problem with the enums/values I provide
  • It's not a problem with the offsetof macro. I tried using hard-coded values and they didn't work either.
  • It's not a compatibility issue with GLint, I use simple 32bit Ints (checked this with sizeof(int))
  • I need to use FluidID as a instanced attrib that indexes into the color array because otherwise, if I were to set the color for a particle group as a simple vec3 uniform, I'd have to batch the same particle types (with the same FluidID) together first which means sorting them and it'd be too costly of an operation.
1

There are 1 answers

1
derhass On BEST ANSWER

To me, this seems to be an issue of how you set up the fluidID attribute pointer. Since you use the type int in the shader, you must use glVertexAttribIPointer() to set up the attribute pointer. Attributes you set up with the normal glVertexAttribPointer() function work only for float-based attribute types. They accept integer input, but the data will be converted to float when the shader accesses them.

In oglplus, you apparently have to use VertexArrayAttrib::IPointer() instead of VertexArrayAttrib::Pointer() if you want to work with integer attributes.