Sending attribute to ofShader?

Hello! Doing some work with shaders and trying to figure how to send an attribute to the vertex shader. They’re being loaded from file and a mesh is being drawn so I have this at the moment…

void ofApp::setup{
shader.load("filename");
}

void ofApp::update(){
fbo.begin();
ofClear(0, 0);
shader.begin();
//a bunch of uniforms being sent here
mesh.draw();
shader.end();
fbo.end();
}

void ofApp::draw(){
fbo.draw(0, 0);
}

The mesh is being calculated/updated as a separate function, everything works fine, but for the vertex shader I want to send the index of each vertex (and the size of the mesh, but that’s a uniform) to be able to have some different functions depending on whether the vertex is at the beginning or end of the mesh.

I’m very confused about how to use the void ofShader::setAttribute1f(GLint location, float v1) function to send the index as an attribute.

I hope someone can point me in the right direction. Thanks!

Could you post the code where you build the mesh?

If your mesh is a vboMesh, you can set a buffer of custom attributes for each vertex using setAttributeData. In this case I wanted to pass to the vertex shader a vec3 for each vertex composing the mesh. Let’s say that may mesh has 10 vertices, it means that each vertex has 3 floats, so I have to create a buffer myData with 30 values, and all of them, in my case, are float.
Before to do this, i have to tell to my shader what is the name of this buffer.

int attLoc = shader.getAttributeLocation("myCustomVec3Att");

Now my shader knows that at id attLoc there will be a buffer with my data.

int nVertices = 10;
mesh.getVbo().setAttributeData(attLoc, &myData[0], 3,
                                       nVertices*3, GL_STATIC_DRAW,
                                       sizeof(float)*3);

Afer this, at the beginning of the vertex shader I can read this value per vertex with:

in vec3 myCustomVec3Att;

I hope this is clear enough :wink:

1 Like

Thanks @edapx, this looks clear enough, gonna attempt it this afternoon!

The mesh is being built based upon one of the algorithms @zach has on his GitHub, drawing lines with thickness functions. So I have a vector of points from which I’m building a ofVboMesh.

Something like this

if(drawing){
//at this point points are being added to the poly line so the mesh needs to be updated.
        ofVboMesh meshy;
        meshy.setMode(OF_PRIMITIVE_TRIANGLE_STRIP);
        
        float widthSmooth = 10;
        float angleSmooth;
        
        
        for (int i = 0;  i < line.getVertices().size(); i++){
            int me_m_one = i-1;
            int me_p_one = i+1;
            if (me_m_one < 0) me_m_one = 0;
            if (me_p_one ==  line.getVertices().size()) me_p_one =  line.getVertices().size()-1;
            ofPoint diff = line.getVertices()[me_p_one] - line.getVertices()[me_m_one];
            float angle = atan2(diff.y, diff.x);
            float dist = diff.length();
            ofPoint offset;
            offset.x = cos(angle + PI/2) * thickness;
            offset.y = sin(angle + PI/2) * thickness;
            meshy.addVertex(  line.getVertices()[i] +  offset );
            meshy.addVertex(  line.getVertices()[i] -  offset );
        }
        
        ofSetColor(color);
        mesh = meshy;
        meshy.draw();
        
    } else {
        
        mesh.draw();
    }
}

So with i/line.getVertices.size() I’ll get a normalised index sort of whether the mesh vertex is close to the beginning or end of the original polyline and will be displaced accordingly. :slight_smile:

By the way, is the value that you want to pass as an attribute, simply the index of the vertex that compose one of the triangle of the mesh? because in this case I think there is already something built in, like gl_VertexID, maybe it worths to give a try before to add a buffer for something that is already there.

Hmm, indeed, according to the documentation of GLES3.0 (I’m running this on an iPad with glesVersion = OFXIOS_RENDERER_ES3) it is supposed to be built in: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/gl_VertexID.xhtml

But…
I’m getting errors.

ERROR: 0:47: Use of undeclared identifier 'gl_VertexID'

and if I add in in highp int gl_VertexID; as per the documentation,
ERROR: 0:6: Invalid storage qualifiers 'in' in global variable context

Not sure what I’m doing wrong here

Here’s the full error log:

[ error ] ofShader: setupShaderFromSource(): GL_VERTEX_SHADER shader failed to compile
[ error ] ofShader: GL_VERTEX_SHADER shader reports:
ERROR: 0:1: Invalid storage qualifiers 'in' in global variable context
ERROR: 0:47: Use of undeclared identifier 'gl_VertexID'

to use that syntax in opengles 3 you need to set the version of the shader to ES3 at the beginning as in:

#version 300 es

Okay, weird, I get this now

[ error ] ofShader: setupShaderFromSource(): GL_VERTEX_SHADER shader failed to compile
[ error ] ofShader: GL_VERTEX_SHADER shader reports:
ERROR: 0:1: '' :  version '300' is not supported
ERROR: 0:1: '' : syntax error: #version

This is a iPad Pro 12.9 inch that’s supposed to be able to handle GLES3 no problem.

Here’s my main.mm file as well, if I’m missing something here.

int main() {
    
    //  here are the most commonly used iOS window settings.
    //------------------------------------------------------
    ofiOSWindowSettings settings;
    settings.enableRetina = true; // enables retina resolution if the device supports it.
    settings.enableDepth = false; // enables depth buffer for 3d drawing.
    settings.enableAntiAliasing = true; // enables anti-aliasing which smooths out graphics on the screen.
    settings.numOfAntiAliasingSamples = 0; // number of samples used for anti-aliasing.
    settings.enableHardwareOrientation = false; // enables native view orientation.
    settings.enableHardwareOrientationAnimation = false; // enables native orientation changes to be animated.
    settings.glesVersion = OFXIOS_RENDERER_ES3; // type of renderer to use, ES1, ES2, ES3
    settings.windowControllerType = ofxiOSWindowControllerType::GL_KIT; // Window Controller Type
    settings.colorType = ofxiOSRendererColorFormat::RGBA8888; // color format used default RGBA8888
    settings.depthType = ofxiOSRendererDepthFormat::DEPTH_16; // depth format (16/24) if depth enabled
    settings.stencilType = ofxiOSRendererStencilFormat::STENCIL_8 ; // stencil mode
    settings.windowMode = OF_FULLSCREEN;
    settings.enableMultiTouch = true;
    ofCreateWindow(settings);
    
    
	return ofRunApp(new ofApp);
}

i’m really not sure that we support GLES 3. definitely OF core doesn’t support it not sure if you can at least compile 300es shaders

I guess I can’t :cry:

So back to the original question that @edapx answered and I try to send the vertexID as an attribute.

PS. Filing an issue on Github too hopefully OF will support GLES3 at some point.

Hey @edapx so the myData buffer is a standard vector<glm::vec3> in your example - where you’re pushing the data in for each vertex?

nope, the myData, in my case, it is an array of floats.

int nVertices = mesh.getVertices().size();
int n = nVertices*3; // number of floats needed to make a vec3
float myData[n];       // each vertex has 3 floats

In your case, you are going to make an array of integer, and each vertex has one index passed as attribute.

int nVertices = mesh.getVertices().size();
float yourData[nVertices];       // each vertex has 1 integer

Once you have that array with your values, you have to:

mesh.getVbo().setAttributeData(attLoc, &myData[0], 1,
                                       nVertices, GL_STATIC_DRAW,
                                       sizeof(int));

I would put attLoc in a global variable in your App.h file, and set its value as soon as you setup the shader.

1 Like

Yup thanks! I figured it out in the meanwhile, yes! And now that I’m sending the data I decided to send a float2, the index and the distance from the original vertex of the polyline :slight_smile:

It runs fine, apart from the fact that I need to break apart my mesh generation and drawing code into separate blocks coz building up the mesh and updating the data array is, for obvious reasons, causing a few issues.

Thanks so much for helping me figure this out :slight_smile:

1 Like

Unrelated to the main question, but @arturo, you are right, GLES3.0 actually doesn’t compile and there’s a ofLog notice that I didn’t notice earlier.

2019-02-20 14:02:49.263862+0200 soundFormInit[2931:787147] [DYMTLInitPlatform] platform initialization successful
2019-02-20 14:02:49.363400+0200 soundFormInit[2931:787118] OpenGLES 3.0 Renderer not implemented for oF. Defaulting to OpenGLES 2.0
2019-02-20 14:02:49.377323+0200 soundFormInit[2931:787118] Metal GPU Frame Capture Enabled
2019-02-20 14:02:49.377703+0200 soundFormInit[2931:787118] Metal API Validation Enabled
2019-02-20 14:02:49.408257+0200 soundFormInit[2931:787118] Creating OpenGL ES2 Renderer