2
votes

In general what I want is to read a specific vbo buffer in a custom way: i have a buffer-> an array of 3 of class Triangle

class Triangle {
public:
    CD_FLOAT3 a;
    CD_FLOAT3 b;
    CD_FLOAT3 c;

    CD_FLOAT3 direction;
    CD_FLOAT velocity;
    CD_FLOAT3 color;
}

This is how i generate the vbo:

GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, size, 0, GL_DYNAMIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);

And what I want from my render function is to render the 3 Vertices of the triangle than to skip for the stride as the sizeof(Triangle) (the next element). So i position the glVertexPointer to the 3 position of the points A,B,C accordingly. I only want one color ont the triangle as well, so i am using one glColorPointer

glBindBufferARB(GL_ARRAY_BUFFER_ARB, vbo);

glVertexPointer( 3, GL_FLOAT, sizeof(Triangle),  0);
glVertexPointer(3, GL_FLOAT, sizeof(Triangle),  (void*)12);
glVertexPointer(3, GL_FLOAT, sizeof(Triangle),  (void*)24);

glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, sizeof(Triangle), (void*)(sizeof(CD_FLOAT)*13));

glDrawArrays(GL_TRIANGLES, 0, numTriangles);
glDisableClientState(GL_COLOR_ARRAY);

The result of this function only draws one triangle, one point per stride, i think that the "glVertexPointer" only repositions the pointer so only the third triangle is drawn.

What i really want to know how can i make the reading of the buffer for the draw of the 3 triangles with:

  1. Triangle1: a; b; c; color; STRIDE:
  2. Triangle2: a; b; c; color; STRIDE
  3. Triangle3: a; b; c; color;
2
Why do you club other data with the data fed to shaders? Uploading data unnecessary for the GPU and then asking it to skip, can me made to work, but it's really not recommended; just upload what you absolutely need. If I understand you rightly, will you upload the whole of Triangle for each triangle rendered?legends2k
Why are you calling glVertexPointer() three times? Only the last call before glDrawArrays() will have any effect.genpfault
@legends2k I know that it is not usefull to send the data to the shaders but that doesnt concern me now. how can i specify to call three times afteranother, is there another gl call?Darwly
@genpfault how can i specify to call three times afteranother, is there another gl call?Darwly

2 Answers

1
votes

You can't do what you want with fixed-function OpenGL.

Best you can do is duplicate your color attribute information and split off your kinematics state:

class Vertex {
public:
    CD_FLOAT3 pos;
    CD_FLOAT3 color;
};

class State {
public:
    CD_FLOAT3 direction;
    CD_FLOAT velocity;
};

const unsigned int NumTris = ...;
std::vector< State > states( NumTris );
std::vector< Vertex > verts( NumTris * 3 );

PopulateAndBindVBO();

glVertexPointer( 3, GL_FLOAT, sizeof(Vertex), 0 );
glColorPointer( 3, GL_FLOAT, sizeof(Vertex), sizeof(CD_FLOAT3) );
glDrawArrays(GL_TRIANGLES, 0, NumTris );    

You could use a geometry shader to split out an array of your Triangle structs into triangles though:

#include <GL/glew.h>
#include <GL/freeglut.h>
#include <iostream>
#include <vector>
#include <cstddef>
using namespace std;

#include <glm/glm.hpp>
using namespace glm;

struct Program
{
    static GLuint Load( const char* vert, const char* geom, const char* frag )
    {
        GLuint prog = glCreateProgram();
        if( vert ) AttachShader( prog, GL_VERTEX_SHADER, vert );
        if( geom ) AttachShader( prog, GL_GEOMETRY_SHADER, geom );
        if( frag ) AttachShader( prog, GL_FRAGMENT_SHADER, frag );
        glLinkProgram( prog );
        CheckStatus( prog );
        return prog;
    }

private:
    static void CheckStatus( GLuint obj )
    {
        GLint status = GL_FALSE;
        if( glIsShader(obj) ) glGetShaderiv( obj, GL_COMPILE_STATUS, &status );
        if( glIsProgram(obj) ) glGetProgramiv( obj, GL_LINK_STATUS, &status );
        if( status == GL_TRUE ) return;
        GLchar log[ 1 << 15 ] = { 0 };
        if( glIsShader(obj) ) glGetShaderInfoLog( obj, sizeof(log), NULL, log );
        if( glIsProgram(obj) ) glGetProgramInfoLog( obj, sizeof(log), NULL, log );
        std::cerr << log << std::endl;
        exit( -1 );
    }

    static void AttachShader( GLuint program, GLenum type, const char* src )
    {
        GLuint shader = glCreateShader( type );
        glShaderSource( shader, 1, &src, NULL );
        glCompileShader( shader );
        CheckStatus( shader );
        glAttachShader( program, shader );
        glDeleteShader( shader );
    }
};

#define GLSL(version, shader) "#version " #version "\n" #shader

struct Triangle
{
    glm::vec3 a;
    glm::vec3 b;
    glm::vec3 c;
    glm::vec3 color;

    glm::vec3 direction;
    GLfloat velocity;
};


const char* vert = GLSL
(
    330 core,
    layout ( location = 0 ) in vec3 A;
    layout ( location = 1 ) in vec3 B;
    layout ( location = 2 ) in vec3 C;
    layout ( location = 3 ) in vec3 Color;

    out VertToGeom
    {
        vec3 A;
        vec3 B;
        vec3 C;
        vec3 Color;
    } outData;

    void main()
    {
        outData.A = A;
        outData.B = B;
        outData.C = C;
        outData.Color = Color;
    }
);

const char* geom = GLSL
(
    330 core,

    in VertToGeom
    {
        vec3 A;
        vec3 B;
        vec3 C;
        vec3 Color;
    } inData[];

    out GeomToFrag
    {
        vec3 Color;
    } outData;

    layout ( points ) in;
    layout ( triangle_strip, max_vertices = 3 ) out;
    void main()
    {
        gl_Position.xyz = inData[ 0 ].A;
        outData.Color = inData[ 0 ].Color;
        EmitVertex();
        gl_Position.xyz = inData[ 0 ].B;
        outData.Color = inData[ 0 ].Color;
        EmitVertex();
        gl_Position.xyz = inData[ 0 ].C;
        outData.Color = inData[ 0 ].Color;
        EmitVertex();
        EndPrimitive();
    }
);

const char* frag = GLSL
(
    330 core,
    in GeomToFrag
    {
        vec3 Color;
    } inData;

    void main()
    {
        gl_FragColor = vec4( inData.Color, 1.0 );
    }
);

GLuint vbo = 0;
void display()
{
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    static GLuint prog = Program::Load( vert, geom, frag );
    glUseProgram( prog );

    vector< Triangle > tris( 2 );
    tris[0].a = glm::vec3( 0, 0, 0 );
    tris[0].b = glm::vec3( 1, 0, 0 );
    tris[0].c = glm::vec3( 1, 1, 0 );
    tris[0].color = glm::vec3( 1, 0, 0 );
    tris[1].a = glm::vec3( 0, 0, 0 );
    tris[1].b = glm::vec3( -1, 0, 0 );
    tris[1].c = glm::vec3( -1, -1, 0 );
    tris[1].color = glm::vec3( 0, 1, 0 );

    glBindBuffer( GL_ARRAY_BUFFER, vbo );
    glBufferData( GL_ARRAY_BUFFER, sizeof( Triangle ) * tris.size(), &tris[0], GL_STREAM_DRAW );

    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, sizeof( Triangle ), (void*)( sizeof( glm::vec3 ) * 0 ) );
    glEnableVertexAttribArray( 0 );
    glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, sizeof( Triangle ), (void*)( sizeof( glm::vec3 ) * 1 ) );
    glEnableVertexAttribArray( 1 );
    glVertexAttribPointer( 2, 3, GL_FLOAT, GL_FALSE, sizeof( Triangle ), (void*)( sizeof( glm::vec3 ) * 2 ) );
    glEnableVertexAttribArray( 2 );
    glVertexAttribPointer( 3, 3, GL_FLOAT, GL_FALSE, sizeof( Triangle ), (void*)( sizeof( glm::vec3 ) * 3 ) );
    glEnableVertexAttribArray( 3 );

    glDrawArrays( GL_POINTS, 0, tris.size() );

    glutSwapBuffers();
}

int main(int argc, char **argv)
{
    glutInit( &argc, argv );
    glutSetOption( GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS );
    glutInitContextVersion( 3, 3 );
    glutInitContextProfile( GLUT_CORE_PROFILE );
    glutInitDisplayMode( GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE );
    glutInitWindowSize( 600, 600 );
    glutCreateWindow( "GLUT" );

    glewExperimental = GL_TRUE;
    glewInit();

    GLuint vao = 0;
    glGenVertexArrays( 1, &vao );
    glBindVertexArray( vao );

    glGenBuffers( 1, &vbo );

    glutDisplayFunc( display );
    glutMainLoop();
    return 0;
}
0
votes

you can try "glVertexAttribPointer" https://www.opengl.org/sdk/docs/man/html/glVertexAttribPointer.xhtml

I think you can store your data like this:

struct vertex
{
    //posision
    float x;
    float y;
    float z;
    //color
    float r;
    float g;
    float b;
}

GLuint buffer;
static const vertex vertices[]={....};
glGenBuffers(1,&buffer);
glBindBuffer(GL_ARRAY_BUFFER,buffer);
glBufferData(GL_ARRAY_BUFFER,sizeof(vertices),vertices,GL_STATIC_DRAW);

//set up two vertex attributes---first positions
glVertexAttribPointer(0,3,GL_FLOAT,GL_FALSE,sizeof(vertex),(void*)offsetof(vertex,x));
glEnableVertexAttribArray(0);
//now colors
glVertexAttribPointer(1,3,GL_FLOAT,GL_FALSE,sizeof(vertex),(void*)offsetof(vertex,r));
glEnableVertexAttribArray(1);