🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

OpenGL transform feedback

Started by
13 comments, last by taby 3 years, 7 months ago

I'm under the impression that you can read back into the CPU memory the triangles that are emitted from a geometry shader. I just can't make it work.

The project is at https://github.com/sjhalayka/opengl_gs_transform_feedback

Any ideas on how to do this so-called transform feedback?

Advertisement

I found a comprehensive code that reads the out variables of a geometry shader. It's close, and I can make it work, but it's kind of a hack. I was hoping that I'd be able to read the triangles emitted.

https://open.gl/feedback

https://open.gl/content/code/c8_final.txt

…I was hoping that I'd be able to read the triangles emitted.

-lol- (respectfully) u sound like a diva now ?

have u not even inspected the code on that c8_final.txt?? that's exactly what it does!

… and it's not a hack;

come on, have another look ?

LOL

OK, there’s two outs in the geometry shader; one‘s the triangles and one’s the floating point variable. If I take out the floating point variable, is there still a way to read the triangles?

P.S. How can you say that it's what I want, when it only spits out 5x3 =15 floats, instead of 5 x 3 x 3 = 45 that are actually required to describe the 5 triangles? I was thinking of making 3 floating point variables.

?

For each value in this data field GLfloat data[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; the geometry shader is outputting a triangle.

//pseudo
- data[0] goes to vertex shader
- vertex shader computes geovalue[0] = sqrt of data[0] and passes it to geom shader
- geom shader receives geovalue and outputs 3 vertices:
	- emit vertex : geovalue[0] + 0
	- emit vertex : geovalue[0] + 1
	- emit vertex : geovalue[0] + 2

- data[1] goes to vertex shader
- vertex shader computes geovalue[0] = sqrt of data[1] and passes it to geom shader
- geom shader receives geovalue and outputs 3 vertices:
	- emit vertex : geovalue[0] + 0
	- emit vertex : geovalue[0] + 1
	- emit vertex : geovalue[0] + 2

- data[2] goes to the pub and asks for a beer
- vertex shader asks r u really here for a beer? see geom shader
- geom shader is already drunk and pukes 3 times:
	- ...
...
i'm not even gonna tell u what happens to data[3] and data[4], the voting count had to stop without evidence :-)	

and

GLfloat feedback[15];
glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(feedback), feedback);

for (int i = 0; i < 15; i++) 
    printf("%f\n", feedback[i]);

feedback then captures all 15 emitted verts;

That's it … all the best ?

ROFL

There's not enough data to describe the triangles though. There's 15 floats, not 15 verts.

P.S. thanks for your time and patience!

OK, so I changed the code to use vec4s instead of floats, and it's working well. My question still stands… Do I absolutely have to use a vec4 out variable?

Major problem: as soon as I attempt to add in a second out variable, I get zero primitives generated.

#include <GL/glew.h>
#include <GL/glut.h>



#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <glm/mat4x4.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;


#include <iostream>
#include <vector>
using namespace std;


// Automatically link in the GLUT and GLEW libraries if compiling on MSVC++
#ifdef _MSC_VER
#pragma comment(lib, "glew32")
#pragma comment(lib, "freeglut")
#endif


// Vertex shader
const GLchar* vertexShaderSrc = R"glsl(
    #version 150 core

    //in vec4 inValue;
    out vec4 geoValue;

    void main()
    {
        geoValue = vec4(1, 2, 3, 4);//inValue;
    }
)glsl";

// Geometry shader
const GLchar* geoShaderSrc = R"glsl(
    #version 150 core

    layout(points) in;
    layout(triangle_strip, max_vertices = 3) out;

    in vec4[] geoValue;
    out vec4 outValue;
    out vec4 outvalue2;


    void main()
    {
        for (int i = 0; i < 3; i++)
        {
            outValue = geoValue[0] + vec4(i, i, i, i);
            EmitVertex();
        }

        EndPrimitive();
    }

)glsl";


int main(int argc, char **argv)
{

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
    glutInitWindowSize(10, 10);
    glutInitWindowPosition(0, 0);

    GLint win_id = glutCreateWindow("GS Test");

    if (GLEW_OK != glewInit())
    {
        cout << "GLEW initialization error" << endl;
        return 0;
    }

    int GL_major_version = 0;
    glGetIntegerv(GL_MAJOR_VERSION, &GL_major_version);

    int GL_minor_version = 0;
    glGetIntegerv(GL_MINOR_VERSION, &GL_minor_version);

    if (GL_major_version < 4)
    {
        cout << "GPU does not support OpenGL 4.3 or higher" << endl;
        return 0;
    }
    else if (GL_major_version == 4)
    {
        if (GL_minor_version < 3)
        {
            cout << "GPU does not support OpenGL 4.3 or higher" << endl;
            return 0;
        }
    }


    // Compile shaders
    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(vertexShader, 1, &vertexShaderSrc, nullptr);
    glCompileShader(vertexShader);

    GLuint geoShader = glCreateShader(GL_GEOMETRY_SHADER);
    glShaderSource(geoShader, 1, &geoShaderSrc, nullptr);
    glCompileShader(geoShader);

    // Create program and specify transform feedback variables
    GLuint program = glCreateProgram();
    glAttachShader(program, vertexShader);
    glAttachShader(program, geoShader);

    const GLchar* feedbackVaryings[] = { "outValue", "outvalue2" };
    glTransformFeedbackVaryings(program, 2, feedbackVaryings, GL_INTERLEAVED_ATTRIBS);

    glLinkProgram(program);
    glUseProgram(program);

    // Create VAO
    GLuint vao;
    glGenVertexArrays(1, &vao);
    glBindVertexArray(vao);

    size_t num_vertices = 1;
    size_t num_vertices_per_triangle = 3;
    size_t num_floats_per_vertex = 4;
    

    // Create input VBO and vertex format
    //vector<GLfloat> data = { 5.0f, 6.0f, 7.0f, 0.0f };

    //GLuint vbo;
    //glGenBuffers(1, &vbo);
    //glBindBuffer(GL_ARRAY_BUFFER, vbo);
    //glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat)*num_vertices*num_floats_per_vertex, &data[0], GL_STATIC_DRAW);

    //GLint inputAttrib = glGetAttribLocation(program, "inValue");
    //glEnableVertexAttribArray(inputAttrib);
    //glVertexAttribPointer(inputAttrib, 1, GL_FLOAT, GL_FALSE, 0, 0);

    // Create transform feedback buffer
    GLuint tbo;
    glGenBuffers(1, &tbo);
    glBindBuffer(GL_ARRAY_BUFFER, tbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 2 * num_vertices * num_vertices_per_triangle * num_floats_per_vertex, nullptr, GL_STATIC_READ);

    // Create query object to collect info
    GLuint query;
    glGenQueries(1, &query);

    // Perform feedback transform
    glEnable(GL_RASTERIZER_DISCARD);

    glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo);

    glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query);
    glBeginTransformFeedback(GL_TRIANGLES);
    glDrawArrays(GL_POINTS, 0, 1);
    glEndTransformFeedback();
    glEndQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);

    glDisable(GL_RASTERIZER_DISCARD);

    glFlush();

    // Fetch and print results
    GLuint primitives;
    glGetQueryObjectuiv(query, GL_QUERY_RESULT, &primitives);

    vector<GLfloat> feedback(2 * num_vertices * num_vertices_per_triangle * num_floats_per_vertex);
    glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(GLfloat)*feedback.size(), &feedback[0]);

    printf("%u primitives written!\n\n", primitives);

    for (int i = 0; i < 2 * num_vertices * num_vertices_per_triangle * num_floats_per_vertex; i++)
    {
        cout << feedback[i] << endl;
    }

    glDeleteQueries(1, &query);

    glDeleteProgram(program);
    glDeleteShader(geoShader);
    glDeleteShader(vertexShader);

    glDeleteBuffers(1, &tbo);
    //glDeleteBuffers(1, &vbo);

    glDeleteVertexArrays(1, &vao);


	return 0;
}

Holy cow, I figured it out. The shader will not link on my AMD Ryzen 3. It links fine on an Intel box. WTF?

@ddlox I've implemented Marching Cubes in a geometry shader. All I need is one vec3 output, right?

This topic is closed to new replies.

Advertisement