Hi,
I’m trying to use Transform Feedback with Geometry Shader to modify vertex number to be rendered. glDrawTransformFeedback
and two transform feedback objects are used to draw the number of vertices captured after geometry shader.
The test program is simplified as
- feed a VBO with single float data with initial value (10.0f)
- in geometry shader, increase the value by 1, emit vertex only if the value is less than (12.0f).
Those numbers above are arbitrary.
#include "cinder/app/App.h"
#include "cinder/app/RendererGl.h"
#include "cinder/gl/gl.h"
using namespace ci;
using namespace ci::app;
using namespace std;
static const std::string vertexSrc = R"END(
#version 330 core
layout (location = 0)
in float inValue;
out float vsValue;
void main()
{
vsValue = inValue;
}
)END";
static const std::string geomSrc = R"END(
#version 330 core
layout (points) in;
layout (points, max_vertices = 1) out;
in float vsValue[];
out float outValue;
void main()
{
if (vsValue[0] < 12)
{
outValue = vsValue[0] + 1;
EmitVertex();
EndPrimitive();
}
}
)END";
class TestTransformFeedbackObjectApp : public App {
public:
void setup() override;
void update() override;
void draw() override;
void loadBuffers();
void loadShaders();
void printBuffers();
gl::VaoRef mVao[2];
gl::TransformFeedbackObjRef mTfo[2];
gl::VboRef mVbo[2];
// 0 or 1, used as index accesing above buffers
int mSourceIndex;
bool bFirstTime;
gl::GlslProgRef mFeedbackGlsl;
gl::QueryRef mQuery;
};
void TestTransformFeedbackObjectApp::loadBuffers()
{
float data[] = { 10.0f };
for (int i = 0; i < 2; ++i)
{
mVao[i] = gl::Vao::create();
mVao[i]->bind();
if (i == 0)
{
mVbo[i] = gl::Vbo::create(GL_ARRAY_BUFFER, sizeof(data), data);
}
else
{
mVbo[i] = gl::Vbo::create(GL_ARRAY_BUFFER, sizeof(data), nullptr);
}
mVbo[i]->bind();
gl::vertexAttribPointer(0, 1, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT), (const GLvoid*)0);
gl::enableVertexAttribArray(0);
mVbo[i]->unbind();
mVao[i]->unbind();
mTfo[i] = gl::TransformFeedbackObj::create();
mTfo[i]->bind();
gl::bindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, mVbo[i]);
mTfo[i]->unbind();
}
mSourceIndex = 0;
}
void TestTransformFeedbackObjectApp::loadShaders()
{
gl::GlslProg::Format format;
format.vertex(vertexSrc).geometry(geomSrc).feedbackVaryings({ "outValue" })
.feedbackFormat(GL_INTERLEAVED_ATTRIBS);
mFeedbackGlsl = gl::GlslProg::create(format);
}
void TestTransformFeedbackObjectApp::printBuffers()
{
GLfloat data;
mVbo[mSourceIndex]->getBufferSubData(0, sizeof(data), &data);
console() << " Source Index: " << mSourceIndex << std::endl;
console() << " data: " << data << std::endl;
mVbo[1 - mSourceIndex]->getBufferSubData(0, sizeof(data), &data);
console() << " Target Index: " << 1 - mSourceIndex << std::endl;
console() << " data: " << data << std::endl;
}
void TestTransformFeedbackObjectApp::setup()
{
loadBuffers();
loadShaders();
bFirstTime = true;
mQuery = gl::Query::create(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
}
void TestTransformFeedbackObjectApp::update()
{
gl::ScopedGlslProg scpGlsl(mFeedbackGlsl);
gl::ScopedState scpState(GL_RASTERIZER_DISCARD, true);
// transform feedback source
gl::ScopedVao scpVao(mVao[mSourceIndex]);
// transform feedback target
mTfo[1 - mSourceIndex]->bind();
console() << "\n[Before feedback]: " << std::endl;
printBuffers();
mQuery->begin();
gl::beginTransformFeedback(GL_POINTS);
if (bFirstTime)
{
gl::drawArrays(GL_POINTS, 0, 1);
bFirstTime = false;
}
else
{
glDrawTransformFeedback(GL_POINTS, mTfo[mSourceIndex]->getId());
}
gl::endTransformFeedback();
mQuery->end();
console() << "** Primitive written: " << mQuery->getValueUInt() << std::endl;
console() << "[After feedback]: " << std::endl;
printBuffers();
mSourceIndex = 1 - mSourceIndex;
}
void TestTransformFeedbackObjectApp::draw()
{
gl::clear(Color(0, 0, 0));
}
CINDER_APP(TestTransformFeedbackObjectApp, RendererGl)
This test program output differently on two platform,
- Window 10, NVidia GTX1050, OpenGL 4.5
- macOS, NVdia GTM 650, OpenGL 4.1
Theoretically, the GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
value should be 1 for two times, as the transform varying value exceeds . After that, it should be 0.
On Windows machine, the program works as intended, which is not the case on macOS, it seems that glDrawTransformFeedback
did not derived the the number of vertices from the transform feedback object.
I’m wondering if this is OpenGL implementation related or I just missed something in the code. Thank you!