PDA

View Full Version : TransformFeedback in-shader specification



john_connor
10-20-2016, 03:28 AM
hi everyone,

i'm trying to replace the call:

glTransformFeedbackVaryings(program, ...)

my application is a simple triangle, but the vertex buffer isnt static, instead i'm using 2 vertex array object + 2 (vertex) buffer objects + 2 transform feedback object:
--> the VAOs + VBOs are set up similarly, as well as the transform feedback object
--> but the transform feedback buffers are doing "buffer pingpong-ing", building a kind of double-buffered vertex array object



struct Vertex
{
vec4 Position;
vec4 Color;
};

unsigned int vertexarray[2] = { 0 };
unsigned int vertexbuffer[2] = { 0 };
unsigned int transformfeedback[2] = { 0 };

glGenVertexArrays(2, vertexarray);
glGenBuffers(2, vertexbuffer);
glGenTransformFeedbacks(2, transformfeedback);

// then the setup for vertex buffer pingponging ...

for (unsigned int i = 0; i < 2; i++)
{
glBindVertexArray(vertexarray[i]);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer[i]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), vertices.data(), GL_DYNAMIC_COPY);
glVertexAttribPointer(0, 4, GL_FLOAT, false, sizeof(Vertex), (void*)(sizeof(float) * 0));
glVertexAttribPointer(1, 4, GL_FLOAT, false, sizeof(Vertex), (void*)(sizeof(float) * 4));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindVertexArray(0);
}

for (unsigned int i = 0; i < 2; i++)
{
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformfeedback[i]);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vertexbuffer[1 - i]);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
}



the vertex shader for this application is:


#version 450 core

layout (location = 0) in vec4 in_position;
layout (location = 1) in vec4 in_color;

uniform mat4 Model = mat4(1);
uniform mat4 View = mat4(1);
uniform mat4 Projection = mat4(1);

out VS_FS_INTERFACE {
vec4 color;
} vs_out;

out vec4 out_position;
out vec4 out_color;


void main(void)
{
mat4 MVP = Projection * View * Model;
gl_Position = MVP * vec4(in_position.xyz, 1);
vs_out.color = in_color;

out_position = Model * vec4(in_position.xyz, 1);
out_color = in_color;
}


to tell the program object what data to capture, i call:


const char* varyings[] = {
"out_position",
"out_color",
};

glTransformFeedbackVaryings(program, sizeof(varyings) / sizeof(const char*), varyings, GL_INTERLEAVED_ATTRIBS);


THAT WORKS.




now i'm trying to replace that call via "in-shader specification":
(by the way: the transform feedback buffer binding point == 0 for both transform feedback objects)



#version 450 core

layout (location = 0) in vec4 in_position;
layout (location = 1) in vec4 in_color;

uniform mat4 Model = mat4(1);
uniform mat4 View = mat4(1);
uniform mat4 Projection = mat4(1);

out VS_FS_INTERFACE {
vec4 color;
} vs_out;


layout (xfb_buffer = 0) out Feedback {
layout (xfb_offset = 0) vec4 out_position;
layout (xfb_offset = 16) vec4 out_color;
};


void main(void)
{
mat4 MVP = Projection * View * Model;
gl_Position = MVP * vec4(in_position.xyz, 1);
vs_out.color = in_color;

out_position = Model * vec4(in_position.xyz, 1);
out_color = in_color;
}


THAT DOESNT WORK.

i get a link error saying:

error: Varying (named out_position) specified but not present in the program object.
unless i delete call "glTransformFeedbackVaryings(...)"

then the program object works (renders a triangle), but the triangle isnt rotation anymore
as if i'm not capturing any data, in fact: i checked it, downloaded the data from the both buffers via "glGetBufferSubData(...)"
both buffers steadily contain a static triangle, that means the transform feedback doesnt work

what am i doing wrong ???

here the complete source code:


#include <GL/glew.h>
#include <GLFW/glfw3.h>

#include <iostream>
#include <vector>

#include "Shader.h"

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/matrix_transform.hpp>

using namespace glm;


struct Vertex
{
vec4 Position;
vec4 Color;
};


// main functions
void Initialize();
void Render();
void CleanUp();



GLFWwindow* window;

unsigned int vertexbuffer[2] = { 0 };
unsigned int vertexarray[2] = { 0 };

unsigned int vertexshader = 0;
unsigned int fragmentshader = 0;
unsigned int program = 0;

unsigned int transformfeedback[2] = { 0 };


int main(void)
{
/* Initialize the library */
if (!glfwInit())
return -1;

/* Create a windowed mode window and its OpenGL context */
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window)
{
glfwTerminate();
return -1;
}

/* Make the window's context current */
glfwMakeContextCurrent(window);

// init glew
if (glewInit() != GLEW_OK)
{
glfwTerminate();
return -1;
}

Initialize();

/* Loop until the user closes the window */
while (!glfwWindowShouldClose(window))
{
/* Render here */
Render();

/* Swap front and back buffers */
glfwSwapBuffers(window);

/* Poll for and process events */
glfwPollEvents();
}

CleanUp();

glfwTerminate();
return 0;
}


void Initialize()
{
// set window title to OpenGL version
glfwSetWindowTitle(window, (char*)glGetString(GL_VERSION));

glClearColor(0.3f, 0.3f, 0.3f, 0);
glEnable(GL_DEPTH_TEST);

// -------------------------------------------------------------------

// here begins the shader setup:
vertexshader = glCreateShader(GL_VERTEX_SHADER);
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);

program = glCreateProgram();

std::string vertexshader_source = LoadTextFile("shader.vs");
std::string fragmentshader_source = LoadTextFile("shader.fs");

// compile shaders
CompileShader(vertexshader, vertexshader_source);
CompileShader(fragmentshader, fragmentshader_source);

// set variables to capture (must be done before linking the program !!!)
//const char* varyings[] = {
// "out_position",
// "out_color",
//};
//
//glTransformFeedbackVaryings(program, sizeof(varyings) / sizeof(const char*), varyings, GL_INTERLEAVED_ATTRIBS);

// attach shaders to program and link it
LinkProgram(program, { vertexshader, fragmentshader });


// here begins the vertexarray setup:
std::vector<Vertex> vertices = {
// x y z _ r g b a
{ { 0, 0, 0, 0 },{ 1, 0, 0, 1 } },// 1st triangle point
{ { 1, 0, 0, 0 },{ 0, 1, 0, 1 } },// 2nd triangle point
{ { 0, 1, 0, 0 },{ 0, 0, 1, 1 } },// 3rd triangle point
};

// setup buffer and vertex array
glGenVertexArrays(2, vertexarray);
glGenBuffers(2, vertexbuffer);

for (unsigned int i = 0; i < 2; i++)
{
glBindVertexArray(vertexarray[i]);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer[i]);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * vertices.size(), vertices.data(), GL_DYNAMIC_COPY);
glVertexAttribPointer(0, 4, GL_FLOAT, false, sizeof(Vertex), (void*)(sizeof(float) * 0));
glVertexAttribPointer(1, 4, GL_FLOAT, false, sizeof(Vertex), (void*)(sizeof(float) * 4));
glBindBuffer(GL_ARRAY_BUFFER, 0);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glBindVertexArray(0);
}


// setup transformfeedback
glGenTransformFeedbacks(2, transformfeedback);

for (unsigned int i = 0; i < 2; i++)
{
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformfeedback[i]);
glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vertexbuffer[1 - i]);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);
}

}


void Render()
{
// just a rotation animation
static float angle = 0.01;
// NOTE: the angle is const, doesnt vary over time, because the rotation matrix will be applied to an already transformed triangle

mat4 Model = rotate(angle, vec3(0, 1, 0));
mat4 View = lookAt(vec3(0, 0, 3), vec3(0, 0, 0), vec3(0, 1, 0));
mat4 Projection = perspective(radians(45.0f), 1.33f, 0.1f, 10.0f);

// upload uniform variables to shader program
glProgramUniformMatrix4fv(program, glGetUniformLocation(program, "Model"), 1, false, value_ptr(Model));
glProgramUniformMatrix4fv(program, glGetUniformLocation(program, "View"), 1, false, value_ptr(View));
glProgramUniformMatrix4fv(program, glGetUniformLocation(program, "Projection"), 1, false, value_ptr(Projection));

// start capturing process
static unsigned int index = 0;//frame-depedent
index = !index;


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glUseProgram(program);

glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, transformfeedback[index]);
glBeginTransformFeedback(GL_TRIANGLES);

glBindVertexArray(vertexarray[index]);
glDrawArrays(GL_TRIANGLES, 0, 3);
glBindVertexArray(0);

glEndTransformFeedback();
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, 0);

glUseProgram(0);


// DEBUG:
// show the captured data:
std::vector<Vertex> retrieved_data(3);
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, vertexbuffer[1 - index]);
glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(Vertex) * retrieved_data.size(), retrieved_data.data());
glBindBuffer(GL_TRANSFORM_FEEDBACK_BUFFER, 0);

std::cout << "1st vertex position: \t" << retrieved_data[0].Position.x << " " << retrieved_data[0].Position.y << " " << retrieved_data[0].Position.z << std::endl;
std::cout << "2st vertex position: \t" << retrieved_data[1].Position.x << " " << retrieved_data[1].Position.y << " " << retrieved_data[1].Position.z << std::endl;
std::cout << "3st vertex position: \t" << retrieved_data[2].Position.x << " " << retrieved_data[2].Position.y << " " << retrieved_data[2].Position.z << std::endl;

// ...
}


void CleanUp()
{
// destroy buffer and vertex array handles
glDeleteBuffers(2, vertexbuffer);
glDeleteVertexArrays(2, vertexarray);

// destroy shaders and program
glDeleteProgram(program);
glDeleteShader(vertexshader);
glDeleteShader(fragmentshader);

// destroy transformfeedback
glDeleteTransformFeedbacks(2, transformfeedback);

// ...
}


thanks for your advices!