Problems with TransfromFeedback

Started by
2 comments, last by Sponji 10 years, 8 months ago

Hi ! I'm not sure to really get transform feedback usage. They are used to modify a VBO from the GPU, so you can create particulesSystems which move without the CPU, isn't it?

So I tried to make a simple soft where I draw a point and I want to move it on his X axis. But It doesn't... i don't see why...

Here is the code

Instance.vert


#version 400

layout (location = 0) in vec4 position;

out vec4 vPosition;

void main(void)
{
   position.x += 0.5;
   vPosition = position;
}

Main.cpp


#include <stdlib.h>
#include <stdio.h>
#include <iostream>

#include <GL\glew.h>
#include <GL\freeglut.h>

#include <LoadShaders.h>


GLuint render_prog;

GLuint inputVBO;
GLuint outputVBO;
GLuint transformFeedbackObj;
	

GLint render_model_matrix_loc;
GLint render_projection_matrix_loc;

		// A single triangle
static const GLfloat vertex_positions[] =
{
    0, 0, 0.0f, 1.0f,
};

void createShader()
{
	render_prog = glCreateProgram();
	GLuint vsHandle = glCreateShader(GL_VERTEX_SHADER);
	const GLchar* source = ReadShader("instance.vert");
	glShaderSource(vsHandle, 1, &source, 0);
	glCompileShader(vsHandle);

	glAttachShader(render_prog, vsHandle);

	const char* varyings[1] = { "vPosition"};
	glTransformFeedbackVaryings(render_prog, 1, varyings, GL_INTERLEAVED_ATTRIBS);

	glLinkProgram(render_prog);
}


void init()
{
	createShader();

	glGenBuffers(1, &inputVBO);

	glGenBuffers(1, &outputVBO);
	glBindBuffer(GL_ARRAY_BUFFER, outputVBO);
	glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_positions) , (vertex_positions), GL_STATIC_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	glGenTransformFeedbacks(1, &transformFeedbackObj);
	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackObj);
	glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, outputVBO); //So , as I understand outputVBO will be modified by the transfromFeedback using inputVBO
	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);

    glClearColor(0.0f, 0.1f, 0.0f, 1.0f);
}

void moveThePoint()
{
	glEnable(GL_RASTERIZER_DISCARD);
	glUseProgram(render_prog);
	

	glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformFeedbackObj);
	glBeginTransformFeedback(GL_POINTS); //begin the transfromFeedback		
		glBindBuffer(GL_ARRAY_BUFFER, inputVBO); //draw into it
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_positions), vertex_positions, GL_STREAM_DRAW);
		glEnableVertexAttribArray(0);
		glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, (const GLvoid *) 0);
		glDrawArrays(GL_POINTS,0, 1);
		
		glDisableVertexAttribArray(0); //clean
		glBindBuffer(GL_ARRAY_BUFFER, 0);
	glEndTransformFeedback();
	glDisable(GL_RASTERIZER_DISCARD);
	glUseProgram(0);
}

void drawThePoint()
{
	glBindBuffer(GL_ARRAY_BUFFER, outputVBO);
	glEnableClientState(GL_VERTEX_ARRAY);
    glVertexPointer(4, GL_FLOAT, 0, 0);
	glDrawTransformFeedback(GL_POINTS, transformFeedbackObj);
	glDisableClientState(GL_VERTEX_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void display() // Loop
{
    // Setup
	glPointSize(21.0);
    glDisable(GL_DEPTH_TEST);

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	moveThePoint();
	drawThePoint();
	glutSwapBuffers();

}

void Reshape(int width, int height)
{
	glViewport(0, 0 , width, height);
}

int main(int argc, char **argv)
{
	glutInit(&argc, argv);
	glutInitContextFlags(GLUT_DEBUG);
    glutInitWindowSize(1024, 768);
	glutInitContextVersion(4, 0);
    glutInitWindowPosition (140, 140);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
	glutInitContextProfile(GLUT_CORE_PROFILE);
	glutCreateWindow("hello");

	if (glewInit())
	{
		std::cout << "Une erreur est survenue lors de l'init de glew" << std::endl; 
		exit(EXIT_FAILURE);
	}

	init();

	glutDisplayFunc(display);
	glutReshapeFunc(Reshape);

	glutMainLoop();

	
	glDeleteBuffers(1, &inputVBO);
	glDeleteBuffers(1, &outputVBO);
	glDeleteTransformFeedbacks(1, &transformFeedbackObj);

	return 0;
}
Advertisement

If I am not mistaken, you are required to have a vertex array object bound with 4.0 core profile.

I successfully used transform feedback in an experiment to flatten terrain a little while back. Here is the code I used to run the transform feedback portion. :


    _transformProgram.enable();
        glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, _transformer);
            glBindVertexArray(_VAO);
                glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, _yBuffer );
                glEnable(GL_RASTERIZER_DISCARD);
                    glBeginTransformFeedback(GL_POINTS);
                        glDrawArrays(GL_POINTS, 0, _vertexCount);
                    glEndTransformFeedback();
                glDisable(GL_RASTERIZER_DISCARD);
            glBindVertexArray(0);
        glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
    _transformProgram.disable();

My draw call was just a few lines because all the buffers are associated with the VAO:


_renderProgram.enable();
_renderProgram.setUniform("ModelViewProjMat", modelViewProjMat);
glBindVertexArray(_VAO);
glDrawElements(GL_TRIANGLES, _elementCount, GL_UNSIGNED_INT, 0);
_renderProgram.disable();

Edit: see this example as well: https://github.com/progschj/OpenGL-Examples/blob/master/09transform_feedback.cpp

Hi ! I have tried to resolve my example by using a double buffer and double vao but nothing changed.

Then I copied you example but this is still not working.

BUT i have noticed something : I created a blank project where I only initialize Glew and I get back GL_INVALID_ENUM by using glewInit(). So I looked on the net and found gl3w which resolve those problems. I tried to run with python 2.6 the gl3w_gen.py but I get a 404 not found for the file which he is looking for on opengl.org.

Here is the "copied file" using freeglut && glew


#include <stdlib.h>
#include <stdio.h>
#include <iostream>

#include <GL\glew.h>
#include <GL\freeglut.h>
#include <glm.hpp>
#include <gtc\matrix_transform.hpp>
#include <gtc\type_ptr.hpp>

#include <time.h>

#include <vector>
#include <LoadShaders.h>
#define GLExitIfError()                                                         \
{                                                                               \
    GLenum Error = glGetError();                                                \
    switch(Error)                                                                \
    {                                                                            \
        case GL_NO_ERROR :                                                        \
            printf( "%s\n", "NO ERROR"    );                                                                \
        break;                                                                    \
        case GL_INVALID_ENUM :                                                  \
            printf( "%s\n", "GL_INVALID_ENUM" ); \
        break; \
        case GL_INVALID_VALUE : \
            printf("%s\n", "GL_INVALID_VALUE"); \
        break;\
        case GL_INVALID_OPERATION : \
            printf("%s\n", "GL_INVALID_OPERATION"); \
        break; \
        case GL_INVALID_FRAMEBUFFER_OPERATION : \
            printf("%s\n", "GL_INVALID_FRAMEBUFFER_OPERATION"); \
        break; \
        case GL_OUT_OF_MEMORY : \
            printf("%s\n", "GL_OUT_OF_MEMORY"); \
        break; \
        default :\
            printf("%s\n", "Unknow");\
        break;\
    } \
}


bool check_shader_compile_status(GLuint obj)
{
    GLint status;
    glGetShaderiv(obj, GL_COMPILE_STATUS, &status);
    if(status == GL_FALSE)
    {
        GLint length;
        glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &length);
        std::vector<char> log(length);
        glGetShaderInfoLog(obj, length, &length, &log[0]);
        std::cerr << &log[0];
        return false;
    }
    return true;
}

bool check_program_link_status(GLuint obj)
{
    GLint status;
    glGetProgramiv(obj, GL_LINK_STATUS, &status);
    if(status == GL_FALSE)
    {
        GLint length;
        glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &length);
        std::vector<char> log(length);
        glGetProgramInfoLog(obj, length, &length, &log[0]);
        std::cerr << &log[0];
        return false;
    }
    return true;
}

  // the vertex shader simply passes through data
std::string vertex_source =
    "#version 330\n"
    "layout(location = 0) in vec4 vposition;\n"
    "void main() {\n"
    " gl_Position = vposition;\n"
    "}\n";
    
// the geometry shader creates the billboard quads
std::string geometry_source =
    "#version 330\n"
    "uniform mat4 View;\n"
    "uniform mat4 Projection;\n"
    "layout (points) in;\n"
    "layout (triangle_strip, max_vertices = 4) out;\n"
    "out vec2 txcoord;\n"
    "void main() {\n"
    " vec4 pos = View*gl_in[0].gl_Position;\n"
    " txcoord = vec2(-1,-1);\n"
    " gl_Position = Projection*(pos+0.2*vec4(txcoord,0,0));\n"
    " EmitVertex();\n"
    " txcoord = vec2( 1,-1);\n"
    " gl_Position = Projection*(pos+0.2*vec4(txcoord,0,0));\n"
    " EmitVertex();\n"
    " txcoord = vec2(-1, 1);\n"
    " gl_Position = Projection*(pos+0.2*vec4(txcoord,0,0));\n"
    " EmitVertex();\n"
    " txcoord = vec2( 1, 1);\n"
    " gl_Position = Projection*(pos+0.2*vec4(txcoord,0,0));\n"
    " EmitVertex();\n"
    "}\n";
    
// the fragment shader creates a bell like radial color distribution
std::string fragment_source =
    "#version 330\n"
    "in vec2 txcoord;\n"
    "layout(location = 0) out vec4 FragColor;\n"
    "void main() {\n"
    " \n"
    " FragColor = vec4(1.0,0.0,0.0,1);\n"
    "}\n";


GLuint render_program;
GLint View_location;
GLint Projection_location;

void createRenderProgram()
{
    GLuint vertex_shader, geometry_shader, fragment_shader;

    const char *source;
    int length;

    // create and compiler vertex shader
    vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    source = vertex_source.c_str();
    length = vertex_source.size();
    glShaderSource(vertex_shader, 1, &source, &length);
    glCompileShader(vertex_shader);
    if(!check_shader_compile_status(vertex_shader))
    {

        return;
    }
    
    // create and compiler geometry shader
    geometry_shader = glCreateShader(GL_GEOMETRY_SHADER);
    source = geometry_source.c_str();
    length = geometry_source.size();
    glShaderSource(geometry_shader, 1, &source, &length);
    glCompileShader(geometry_shader);
    if(!check_shader_compile_status(geometry_shader))
    {
        return;
    }
 
    // create and compiler fragment shader
    fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
    source = fragment_source.c_str();
    length = fragment_source.size();
    glShaderSource(fragment_shader, 1, &source, &length);
    glCompileShader(fragment_shader);
    if(!check_shader_compile_status(fragment_shader))
    {
        return;
    }

    // create program
    render_program = glCreateProgram();
    
    // attach shaders
    glAttachShader(render_program, vertex_shader);
    glAttachShader(render_program, geometry_shader);
    glAttachShader(render_program, fragment_shader);
    
    // link the program and check for errors
    glLinkProgram(render_program);
    check_program_link_status(render_program);
    
    View_location = glGetUniformLocation(render_program, "View");
    Projection_location = glGetUniformLocation(render_program, "Projection");
}

 // the transform feedback shader only has a vertex shader
std::string transform_vertex_source =
    "#version 330\n"
    "uniform vec3 center[3];\n"
    "uniform float radius[3];\n"
    "uniform vec3 g;\n"
    "uniform float dt;\n"
    "uniform float bounce;\n"
    "uniform int seed;\n"
    "layout(location = 0) in vec3 inposition;\n"
    "layout(location = 1) in vec3 invelocity;\n"
    "out vec3 outposition;\n"
    "out vec3 outvelocity;\n"
        
    "float hash(int x) {\n"
    " x = x*1235167 + gl_VertexID*948737 + seed*9284365;\n"
    " x = (x >> 13) ^ x;\n"
    " return ((x * (x * x * 60493 + 19990303) + 1376312589) & 0x7fffffff)/float(0x7fffffff-1);\n"
    "}\n"
        
    "void main() {\n"
    " outvelocity = invelocity;\n"
    " for(int j = 0;j<3;++j) {\n"
    " vec3 diff = inposition-center[j];\n"
    " float dist = length(diff);\n"
    " float vdot = dot(diff, invelocity);\n"
    " if(dist<radius[j] && vdot<0.0)\n"
    " outvelocity -= bounce*diff*vdot/(dist*dist);\n"
    " }\n"
    " outvelocity += dt*g;\n"
    " outposition = inposition + dt*outvelocity;\n"
    " if(outposition.y < -30.0)\n"
    " {\n"
    " outvelocity = vec3(0,0,0);\n"
    " outposition = 0.5-vec3(hash(3*gl_VertexID+0),hash(3*gl_VertexID+1),hash(3*gl_VertexID+2));\n"
    " outposition = vec3(0,20,0) + 5.0*outposition;\n"
    " }\n"
    "}\n";

GLuint transform_shader_program;
GLint center_location;
GLint radius_location;
GLint g_location;
GLint dt_location;
GLint bounce_location ;
GLint seed_location;
void createUpdateProgram()
{
    GLuint transform_vertex_shader;
    
    const char *source;
    int length;

    transform_vertex_shader = glCreateShader(GL_VERTEX_SHADER);
    source = transform_vertex_source.c_str();
    length = transform_vertex_source.size();
    glShaderSource(transform_vertex_shader, 1, &source, &length);
    glCompileShader(transform_vertex_shader);
    if(!check_shader_compile_status(transform_vertex_shader))
    {
        return;
    }
     // create program
    transform_shader_program = glCreateProgram();
    
    // attach shaders
    glAttachShader(transform_shader_program, transform_vertex_shader);
    
    // specify transform feedback output
    const char *varyings[] = {"outposition", "outvelocity"};
    glTransformFeedbackVaryings(transform_shader_program, 2, varyings, GL_INTERLEAVED_ATTRIBS);
    
    // link the program and check for errors
    glLinkProgram(transform_shader_program);
    check_program_link_status(transform_shader_program);

    center_location = glGetUniformLocation(transform_shader_program, "center");
    radius_location = glGetUniformLocation(transform_shader_program, "radius");
    g_location = glGetUniformLocation(transform_shader_program, "g");
    dt_location = glGetUniformLocation(transform_shader_program, "dt");
    bounce_location = glGetUniformLocation(transform_shader_program, "bounce");
    seed_location = glGetUniformLocation(transform_shader_program, "seed");
}

const int buffercount = 2;
const int particles = 128*1024;
std::vector<glm::vec3> vertexData(2*particles);
GLuint vao[buffercount], vbo[buffercount];

const int spheres = 3;
glm::vec3 center[spheres];
float radius[spheres];

// physical parameters
float dt = 1.0f/60.0f;
glm::vec3 g(0.0f, -9.81f, 0.0f);
float bounce = 1.2f; // inelastic: 1.0f, elastic: 2.0f

int current_buffer=0;

void init()
{
    
    createRenderProgram();
        
    createUpdateProgram();
    for(int i = 0;i<particles;++i)
    {
        // initial position
        vertexData[2*i+0] = glm::vec3(
                                0.5f-float(std::rand())/RAND_MAX,
                                0.5f-float(std::rand())/RAND_MAX,
                                0.5f-float(std::rand())/RAND_MAX
                            );
        vertexData[2*i+0] = glm::vec3(0.0f,20.0f,0.0f) + 5.0f*vertexData[2*i+0];
        
        // initial velocity
        vertexData[2*i+1] = glm::vec3(0,0,0);
    }

    for(int i = 0;i<buffercount;++i)
    {
        glBindVertexArray(vao[i]);
        
        glBindBuffer(GL_ARRAY_BUFFER, vbo[i]);

        // fill with initial data
        glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3)*vertexData.size(), &vertexData[0], GL_STATIC_DRAW);
                        
        // set up generic attrib pointers
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (char*)0 + 0*sizeof(GLfloat));
        // set up generic attrib pointers
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (char*)0 + 3*sizeof(GLfloat));
    }

     // "unbind" vao
    glBindVertexArray(0);
    
    glEnable(GL_BLEND);
    // and set the blend function to result = 1*source + 1*destination
    glBlendFunc(GL_ONE, GL_ONE);

    center[0] = glm::vec3(0,12,1);
    radius[0] = 3;
    center[1] = glm::vec3(-3,0,0);
    radius[1] = 7;
    center[2] = glm::vec3(5,-10,0);
    radius[2] = 12;
}



void display()
{
    long t = time(NULL);

    glUseProgram(transform_shader_program);

    // set the uniforms
        glUniform3fv(center_location, 3, reinterpret_cast<GLfloat*>(center));
        glUniform1fv(radius_location, 3, reinterpret_cast<GLfloat*>(radius));
        glUniform3fv(g_location, 1, glm::value_ptr(g));
        glUniform1f(dt_location, dt);
        glUniform1f(bounce_location, bounce);
        glUniform1i(seed_location, std::rand());

        // bind the current vao
        glBindVertexArray(vao[(current_buffer+1)%buffercount]);

        // bind transform feedback target
        glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vbo[current_buffer]);

        glEnable(GL_RASTERIZER_DISCARD);

        // perform transform feedback
        glBeginTransformFeedback(GL_POINTS);
        glDrawArrays(GL_POINTS, 0, particles);
        glEndTransformFeedback();

        glDisable(GL_RASTERIZER_DISCARD);
   
        // clear first
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
        // use the shader program
        glUseProgram(render_program);
        
        // calculate ViewProjection matrix
        glm::mat4 Projection = glm::perspective(90.0f, 4.0f / 3.0f, 0.1f, 100.f);
        
        // translate the world/view position
        glm::mat4 View = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -30.0f));
        
        // make the camera rotate around the origin
        View = glm::rotate(View, 30.0f, glm::vec3(1.0f, 0.0f, 0.0f));
        View = glm::rotate(View, -22.5f, glm::vec3(0.0f, 1.0f, 0.0f));
        
        // set the uniform
        glUniformMatrix4fv(View_location, 1, GL_FALSE, glm::value_ptr(View));
        glUniformMatrix4fv(Projection_location, 1, GL_FALSE, glm::value_ptr(Projection));
        
        // bind the current vao
        glBindVertexArray(vao[current_buffer]);

        // draw
        glDrawArrays(GL_POINTS, 0, particles);
       
        // check for errors

    
        // finally swap buffers
        glutSwapBuffers();
        
        // advance buffer index
        current_buffer = (current_buffer + 1) % buffercount;
}

void Reshape(int width, int height)
{
    glViewport(0, 0 , width, height);
}

int main(int argc, char **argv)
{
    glutInit(&argc, argv);

    glutInitContextFlags(GLUT_DEBUG);
    glutInitWindowSize(1024, 768);
    glutInitContextVersion(3, 3);
    glutInitWindowPosition (140, 140);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    glutInitContextProfile(GLUT_CORE_PROFILE);
    glutCreateWindow("hello");

    glewExperimental = true;
    if (glewInit() != GLEW_OK)
    {
        std::cout << "Une erreur est survenue lors de l'init de glew" << std::endl;
        exit(EXIT_FAILURE);
    }

    GLExitIfError();
    
    init();

    glutDisplayFunc(display);
    glutReshapeFunc(Reshape);

    glutMainLoop();

    glDeleteVertexArrays(buffercount, vao);
    glDeleteBuffers(buffercount, vbo);
    
    return 0;
}

Maybe someone could help me for debugging ? Because of glew GL_INVALID_ENUM I can't place a glGetError where I want sad.png. Is someone having the same probleme with gl3w? (I 'm on window8).

Here's some explanation about that invalid enum, http://www.opengl.org/wiki/OpenGL_Loading_Library#GLEW

You could probably just ignore the errors from glewInit.

Derp

This topic is closed to new replies.

Advertisement