Transform feedback problem

Hi all,
I have checked the similar thread (http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=242645) but it does not solve my problem. I am trying to do basic transform feedback by converting the nvidia opengl sdk (transform feedback fractal Cg example http://developer.download.nvidia.com/SDK/10/opengl/samples.html) to glsl. In the feedback func. after the calls to


glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vboID[1-current_buffer]);
glBeginTransformFeedback(feedback_prim);
glEnable(GL_RASTERIZER_DISCARD);    // disable rasterization
glBeginQuery(GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, query);

I attach my shaders using (glUseProgram(terrainShader)). After this call however I get no output. I have checked the error bit and its clear.

The shaders are also compiled and linked fine. What may be causing this. One more thing, if i move the shader program before the bindbufferbase call, there is no error but then the feedback does not work and i only get the base triangles without sub division but the query results is correct. If the shader is within the feedback calls given above, the query result is 0.
The terrain geometry shader for subdivision is this


#version 300                                                     

layout (lines_adjacency) in;
layout (points, max_vertices = 16) out;

uniform float rand_scale;// = 1.0,
uniform vec2 rand_xform;// = { 0.5, 0.5 },
uniform sampler2D rand_tex;

out vec4 color;

void main() 
{
 vec4 v[4];
 for(int i=0;i<4;i++) {
  v[i] = gl_in[i].gl_Position;
 }
 // calculate midpoints
 vec4 e0 = (v[0] + v[1]) * 0.5;
 vec4 e1 = (v[1] + v[2]) * 0.5;
 vec4 e2 = (v[2] + v[3]) * 0.5;
 vec4 e3 = (v[3] + v[0]) * 0.5;
 vec4 m = (v[0] + v[1] + v[2] + v[3]) * 0.25;

 // add random offsets
 e0.y += texture(rand_tex, e0.xz*rand_xform.x+rand_xform.y).x*rand_scale;
 e1.y += texture(rand_tex, e1.xz*rand_xform.x+rand_xform.y).x*rand_scale;
 e2.y += texture(rand_tex, e2.xz*rand_xform.x+rand_xform.y).x*rand_scale;
 e3.y += texture(rand_tex, e3.xz*rand_xform.x+rand_xform.y).x*rand_scale;
 m.y += texture(rand_tex, m.xz*rand_xform.x+rand_xform.y).x*rand_scale;

 gl_Position = v[0]; color=vec4(1,0,0,0);	EmitVertex();    
 gl_Position = e0;	color=vec4(1,0,0,0);	EmitVertex();    
 gl_Position = m;	color=vec4(1,0,0,0);	EmitVertex();    
 gl_Position = e3;	color=vec4(1,0,0,0);	EmitVertex();
    
 gl_Position = e0;	color=vec4(0,0,1,0);	EmitVertex();
 gl_Position = v[1];	color=vec4(0,0,1,0);	EmitVertex();
 gl_Position = e1;	color=vec4(0,0,1,0);	EmitVertex();
 gl_Position = m;	color=vec4(0,0,1,0);	EmitVertex();
 
 gl_Position = m;	color=vec4(0,1,0,0);	EmitVertex();
 gl_Position = e1;	color=vec4(0,1,0,0);	EmitVertex();
 gl_Position = v[2];	color=vec4(0,1,0,0);	EmitVertex();
 gl_Position = e2;	color=vec4(0,1,0,0);	EmitVertex();
	 
 gl_Position = e3;	color=vec4(1,0,1,0);	EmitVertex();
 gl_Position = m;	color=vec4(1,0,1,0);	EmitVertex();
 gl_Position = e2;	color=vec4(1,0,1,0);	EmitVertex();
 gl_Position = v[3];	color=vec4(1,0,1,0);	EmitVertex();    
}

and the terrain shading geometry shader is this


#version 330                                                     

layout (lines_adjacency) in;
layout (triangle_strip, max_vertices = 6) out;

vec3 lightDir=vec3(0,0,-1);
 
// calculate triangle normal
vec3 calcNormal(vec3 v0, vec3 v1, vec3 v2)
{
    vec3 edge0 = v1 - v0;
    vec3 edge1 = v2 - v0;
    return normalize(cross(edge0, edge1));
}

in vec4 o_pos[];
in vec2 o_texcoord[];
in vec4 o_wpos[];
in vec4 o_color[];

out vec4 color;
void main() {                                       	
	vec3 n = calcNormal(o_wpos[0].xyz, o_wpos[1].xyz, o_wpos[3].xyz);
	float col = dot(n, lightDir);

	vec3 n2 = calcNormal(o_wpos[1].xyz, o_wpos[2].xyz, o_wpos[3].xyz);
	float col2 = dot(n2, lightDir);

	gl_Position = gl_in[0].gl_Position;
	color = vec4(col);
	EmitVertex();

	gl_Position = gl_in[1].gl_Position;
	color = vec4(col);
	EmitVertex();

	gl_Position = gl_in[3].gl_Position;
	color = vec4(col);
	EmitVertex();

	gl_Position = gl_in[2].gl_Position;
	color = vec4(col2);
	EmitVertex();
}

First, there is a problem with your feedback geometry shader (I suppose the subdivision one is that). You should not output gl_Position in case you do transform feedback only. You have to output all the data you want to store to your feedback buffer using custom output varyings.

Also, I would be interested in your shader setup code to see whether you configure the output varyings for transform feedback correctly.

Thanks for the prompt reply. Here it is (i am using the opengl superbible 5 based gltools lib to load the shaders.


basicShader = gltLoadShaderTripletWithAttributes("PassThrough.vp", "Terrain.gp", "Basic.fp",1, GLT_ATTRIBUTE_VERTEX,"vVertex"); 
terrainShader = gltLoadShaderTripletWithAttributes("XForm.vp", "TerrainDisplay.gp", "Basic.fp", 3, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_TEXTURE0, "vTexCoord",			GLT_ATTRIBUTE_COLOR,"vColor");
gltCheckErrors(); 

b_mvLocation	= glGetUniformLocation(terrainShader, "MV");
b_mvpLocation	= glGetUniformLocation(terrainShader, "MVP");
terrain_rand_scale = glGetUniformLocation(basicShader, "rand_scale");	
terrain_rand_xform = glGetUniformLocation(basicShader, "rand_xform");
	
glUseProgram(basicShader);
glUniform1i(glGetUniformLocation(basicShader, "rand_tex"),0);
glUseProgram(0);
	
gltCheckErrors( ); 

// create buffer objects
glGenBuffers(2, vboID);
glBindBuffer(GL_ARRAY_BUFFER, vboID[0]);
glBufferData(GL_ARRAY_BUFFER, max_buffer_verts*4*sizeof(GLfloat), 0, GL_STATIC_DRAW);

// load initial vertex data
GLfloat v[] = {
    -1.0, 0.0, 0.0, 1.0,
    1.0, 0.0, 0.0, 1.0,
};
glBufferSubData(GL_ARRAY_BUFFER, 0, 2*4*sizeof(GLfloat), v);
glBindBuffer(GL_ARRAY_BUFFER, vboID[1]);
glBufferData(GL_ARRAY_BUFFER, max_buffer_verts*4*sizeof(GLfloat), 0, GL_STATIC_DRAW);

gltCheckErrors( ); 

static const char* names[]={"o_pos"};
glTransformFeedbackVaryings(terrainShader, 1, names, GL_SEPARATE_ATTRIBS);
	
glLinkProgram(terrainShader);

gltCheckErrors( ); 

// create query objects
glGenQueries(1, &query);

I am only using the o_pos attributes since the feedback will generate the new attributes isnt it?

Sorry, don’t quite understand this. Which geometry shader do you use for transform feedback? I don’t see the “o_pos” output in either of the geometry shaders you’ve presented above.

I am a bit confused in this too since I have simply translated the cg shader to glsl. IN the original code, the POSITION semantic is used like this


// specify which attributes to store
GLint attribs[] = { GL_POSITION, 4, 0 };    glTransformFeedbackAttribsNV(1, attribs, GL_SEPARATE_ATTRIBS_NV);

Could I output to gl_Position like this?


static const char* names[]={"gl_Position"};
glTransformFeedbackVaryings(terrainShader, 1, names, GL_SEPARATE_ATTRIBS);

Currently the code uses two vbo reading from one and writing to other. Another question is regarding attaching the vbo to the TRANSFORM_FEEDBACK_BUFFER binding. The original code does not bind the vbo to it but it still works. Should I bind to this? and if yes which of the two vbo should be bound?

GLSL is different from Cg. You cannot use the built-in gl_Position as an output varying for transform feedback. Instead, you have to declare your own custom output varying.

This is required:

glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, vboID[1-current_buffer]);

This tells where to send the feedback data. When you use the feedback data as a VBO you don’t need anymore the TRANSFORM_FEEDBACK_BUFFER binding.

Hi,
OK there are two geometry shaders one for transform feedback (terrain.gp) and another for shading the terrain(terraindisplay.gp). Terrain.gp has a pass through vs as follows,

//passthrough.vs
#version 330                                                     
                   
in vec4 vVertex; 

void main() {                                    
    gl_Position = vVertex;
}

terrain.gp is this

//terrain.gp
#version 330                                                     

layout (lines_adjacency) in;
layout (points, max_vertices = 16) out;

uniform float rand_scale;// = 1.0,
uniform vec2 rand_xform;// = { 0.5, 0.5 },
uniform sampler2D rand_tex;
 
out vec4 o_pos;

void main() 
{
	vec4 v[4];
	for(int i=0;i<4;i++) {
		v[i] = gl_in[i].gl_Position;
	}
    // calculate midpoints
    vec4 e0 = (v[0] + v[1]) * 0.5;
    vec4 e1 = (v[1] + v[2]) * 0.5;
    vec4 e2 = (v[2] + v[3]) * 0.5;
    vec4 e3 = (v[3] + v[0]) * 0.5;
    vec4 m = (v[0] + v[1] + v[2] + v[3]) * 0.25;

    // add random offsets
    e0.y += texture(rand_tex, e0.xz*rand_xform.x+rand_xform.y).x*rand_scale;
    e1.y += texture(rand_tex, e1.xz*rand_xform.x+rand_xform.y).x*rand_scale;
    e2.y += texture(rand_tex, e2.xz*rand_xform.x+rand_xform.y).x*rand_scale;
    e3.y += texture(rand_tex, e3.xz*rand_xform.x+rand_xform.y).x*rand_scale;
    m.y += texture(rand_tex, m.xz*rand_xform.x+rand_xform.y).x*rand_scale;

	o_pos = v[0]; 	EmitVertex();    
	o_pos = e0;	EmitVertex();    
	o_pos = m;	EmitVertex();    
	o_pos= e3;	EmitVertex();
    
	o_pos= e0;	EmitVertex();
    o_pos= v[1];EmitVertex();
    o_pos= e1;	EmitVertex();
    o_pos= m;	EmitVertex();
 

	o_pos= m;	EmitVertex();
    o_pos= e1;	EmitVertex();
    o_pos= v[2];EmitVertex();
    o_pos= e2;	EmitVertex();
	 

	o_pos= e3;	EmitVertex();
    o_pos= m;	EmitVertex();
    o_pos= e2;	EmitVertex();
    o_pos= v[3];EmitVertex();    
}

terraindisplay.gs has xform.vs as the vertex shader which is

//xform.vs
#version 330                                                     
 
out vec4 o_wpos;
in vec4 vVertex;  

uniform mat4 MV,MVP;

void main() {                                       
   gl_Position = MVP*vVertex;	
   o_wpos = MV*vVertex;
}

terraindisplay.gs is this

//terraindisplay.gs
#version 330                                                     

layout (lines_adjacency) in;
layout (triangle_strip, max_vertices = 6) out;

vec3 lightDir=vec3(0,0,-1);
 
// calculate triangle normal
vec3 calcNormal(vec3 v0, vec3 v1, vec3 v2)
{
    vec3 edge0 = v1 - v0;
    vec3 edge1 = v2 - v0;
    return normalize(cross(edge0, edge1));
}
 
in vec4 o_wpos[];  
out vec4 color;
void main() {                                       	
	vec3 n = calcNormal(o_wpos[0].xyz, o_wpos[1].xyz, o_wpos[3].xyz);
	float col = dot(n, lightDir);

	vec3 n2 = calcNormal(o_wpos[1].xyz, o_wpos[2].xyz, o_wpos[3].xyz);
	float col2 = dot(n2, lightDir);

	gl_Position = gl_in[0].gl_Position;
	color = vec4(col);
	EmitVertex();

	gl_Position = gl_in[1].gl_Position;
	color = vec4(col);
	EmitVertex();

	gl_Position = gl_in[3].gl_Position;
	color = vec4(col);
	EmitVertex();

	gl_Position = gl_in[2].gl_Position;
	color = vec4(col2);
	EmitVertex();
}

in the init code i put the trans. feedvk attribute as follows


static const char* names[]={"o_pos"};
glTransformFeedbackVaryings(terrainShader, 1, names, GL_SEPARATE_ATTRIBS);
	
glLinkProgram(terrainShader);

Still I am getting error 1282 after glUseProgram in the feedback func.

I think I have found the reason for the error 1282. The locations of the two uniforms (terrain_rand_scale and terrain_rand_xform) are -1.


terrain_rand_scale = glGetUniformLocation(basicShader, "rand_scale");	
	terrain_rand_xform = glGetUniformLocation(basicShader, "rand_xform");

I am declaring these uniforms only in the geometry shader where they are used. Do i need to declare them in vs and fs also? If not then why I am getting the loc == -1?

Do i need to declare them in vs and fs also?

No, you don’t have to. One possible reason why you get -1 as the uniform location is because the program linkage failed. Have you checked shader compilation and program linkage logs? Are you sure that everything has been compiled and linked successfully?

Yes the program compiled and linked fine no errors.

Ok I am attaching the src. If someone could tell me what I am doing wrong, that would be wonderful. By the way u will need gltools library (opengl superbible5th ed. code) which can be found here http://code.google.com/p/oglsuperbible5/source/checkout

Hi all,
Sorry to bring up my old thread back in. I am asking this since I have not yet been able to solve this problem. I have a question to ask about transform feedback.

When we are outputting the position in the geometry shader I have to output to the gl_Poisition variable right, then how can i output to my attribute? can i output to both my attribute and gl_Position then emitvertex from geometry shader.
Writing to both also did not help?

Any reference that discusses the details of transform feedback are welcomed.

Regards,
Mobeen

Hi all,
I was just reading the GL 4.1 specs. There I see these func. on page 145 core specs GL4.1


glGenTransformFeedbacks(1, &tfID);
glBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tfID);

is it mandetory to call these funcs? If I put these in, the invalid operation that I was getting earlier is gone however it gives me the same error after the glEndTransformFeedback() call. The reason why i ask this is because the OpenGL superbible 5th ed. never discusses these functions. and none of the demos I have seen using transform feedback have called these?

Ok I more update I know the reason for the INVALID_OPERATION error. The transform_feedback specs state that

It is an invalid operation error to call BeginTransformFeedbackNV,
TransformFeedbackVaryingsNV, TransformFeedbackAttribsNV, or UseProgram or
LinkProgram on the currently active program object while transform
feedback is active. It is an invalid operation error to call
EndTransformFeedbackNV while transform feedback is inactive.

and I was calling glUseProgram after calling beginTransformFeedback so this sorts my invalid operation error. So now the transform feedback is ok. the rendering however is giving me error 1280 (INVALID_ENUM) which I think is probably b/c my output primitve type is wrong.

One more thing it is not necessary to call the gen and bind func. i noted above even if i remove them the code works.

Ok got it working now i can see the terrain vertices fine now only thing left now is the lighting. Check the attached image.

So I am almost done now. I will summarize the changes I did to let others know what is needed to get it working.

Hurray!!! I have done it.
The reason I was not getting the light was because I had turned CULLING on :P. Now its perfectly fine. See the attached image.

OK the changes I did and the lessons learnt for myself and others (who may fall into the same trap):

  1. Call glUseProgram before transform feedback not between the call to glBeginTransformFeedback and glEndTransformFeedback.
  2. When outputting the variable from the geometry shader the transform feedback attribute as well as the gl_Position must be written before EmitVertex.
  3. Make sure to use the correct render primitive for drawing the object after the transform feedback.
    To conclude, here are my final shaders, I used basicshader for feedback and the terrainshader for final rendering of terrain.

//basic shader
//passthrough vertex shader (Basic shader)
#version 330     
in vec4 vVertex; 
void main() {              
    gl_Position = vVertex ;
}

//terrain geometry shader (Basic shader)
#version 330                              
layout (lines_adjacency) in;
layout (points, max_vertices = 16) out;
uniform float rand_scale;// = 1.0,
uniform vec2 rand_xform;// = { 0.5, 0.5 },
uniform sampler2D rand_tex;
out vec4 o_pos;
void main() 
{
  vec4 v[4];
  for(int i=0;i<4;i++) {
    v[i] = gl_in[i].gl_Position;
  }
  // calculate midpoints
  vec4 e0 = (v[0] + v[1]) * 0.5;
  vec4 e1 = (v[1] + v[2]) * 0.5;
  vec4 e2 = (v[2] + v[3]) * 0.5;
  vec4 e3 = (v[3] + v[0]) * 0.5;
  vec4 m = (v[0] + v[1] + v[2] + v[3]) * 0.25;

  // add random offsets
  e0.y += texture(rand_tex, e0.xz*rand_xform.x+rand_xform.y).x*rand_scale;
  e1.y += texture(rand_tex, e1.xz*rand_xform.x+rand_xform.y).x*rand_scale;
  e2.y += texture(rand_tex, e2.xz*rand_xform.x+rand_xform.y).x*rand_scale;
  e3.y += texture(rand_tex, e3.xz*rand_xform.x+rand_xform.y).x*rand_scale;
  m.y += texture(rand_tex, m.xz*rand_xform.x+rand_xform.y).x*rand_scale;

  o_pos = v[0]; gl_Position=v[0]; EmitVertex();    
  o_pos = e0;	gl_Position=e0;   EmitVertex();    
  o_pos = m;	gl_Position=m;	  EmitVertex();    
  o_pos= e3;	gl_Position=e3;   EmitVertex();
  o_pos= e0;	gl_Position=e0;	  EmitVertex();
  o_pos= v[1];	gl_Position=v[1]; EmitVertex();
  o_pos= e1;	gl_Position=e1;   EmitVertex();
  o_pos= m;	gl_Position=m;    EmitVertex();
  o_pos= m;	gl_Position=m;	  EmitVertex();
  o_pos= e1;	gl_Position=e1;	  EmitVertex();
  o_pos= v[2];	gl_Position=v[2]; EmitVertex();
  o_pos= e2;	gl_Position=e2;	  EmitVertex();
  o_pos= e3;	gl_Position=e3;	  EmitVertex();
  o_pos= m;	gl_Position=m;	  EmitVertex();
  o_pos= e2;	gl_Position=e2;	  EmitVertex();
  o_pos= v[3];gl_Position=v[3];	  EmitVertex();    
}

//passthough fragment shader (Basic shader)
#version 330  
out vec4 vFragColor;
void main() {                                    
    vFragColor = vec4(1);
}

The shader for rendering terrain used after the transform feedback is this called (terrain shader)


//XForm vertex shader (Terrain shader)
#version 330                                                     
out vec4 o_wpos;
in vec4 vVertex;  
uniform mat4 MV,
 	     MVP;
void main() {                                       
  gl_Position = MVP*vVertex;	
  o_wpos = MV*vVertex;
}

//Terrain display geometry shader (Terrain shader)
#version 330                                 
layout (lines_adjacency) in;
layout (triangle_strip, max_vertices = 6) out;
vec3 lightDir=vec3(0,0,-1);
// calculate triangle normal
vec3 calcNormal(vec3 v0, vec3 v1, vec3 v2)
{
    vec3 edge0 = v1 - v0;
    vec3 edge1 = v2 - v0;
    return normalize(cross(edge0, edge1));
}

in vec4 o_wpos[];  
smooth out vec4 color;
void main() {                                       	
  vec3 n = calcNormal(o_wpos[0].xyz, o_wpos[1].xyz, o_wpos[3].xyz);
  float col = dot(n, lightDir);
  vec3 n2 = calcNormal(o_wpos[1].xyz, o_wpos[2].xyz, o_wpos[3].xyz);
  float col2 = dot(n2, lightDir);
  gl_Position = gl_in[0].gl_Position;
  color = vec4(col);
  EmitVertex();

  gl_Position = gl_in[1].gl_Position;
  color = vec4(col);
  EmitVertex();

  gl_Position = gl_in[3].gl_Position;
  color = vec4(col);
  EmitVertex();

  gl_Position = gl_in[2].gl_Position;
  color = vec4(col2);
  EmitVertex();	
}

//fragment shader (Terrain shader)
#version 330   
smooth in vec4 color;
out vec4 vFragColor;
void main() {  
    vFragColor = color;  
}

Thats it. If anyone needs the full source code, I can attach it here.
Thanks for ur inputs guys.

Kindest regards,
Mobeen

1 Like