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: " << retrieved_data[0].Position.x << " " << retrieved_data[0].Position.y << " " << retrieved_data[0].Position.z << std::endl;
std::cout << "2st vertex position: " << retrieved_data[1].Position.x << " " << retrieved_data[1].Position.y << " " << retrieved_data[1].Position.z << std::endl;
std::cout << "3st vertex position: " << 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!