PDA

View Full Version : geometry shader for cycle problem



esnho
10-05-2011, 01:04 PM
Hi,
I'm new in this forum and I'm new to openGL and shading languages.

I'm writing in GLSL a geometry shader that pick a line strip vertices and transform it to looks like a filled stroke, it's like a tape; it's a triangles strip.

I started my work from this shader https://github.com/openframeworks/openFr...aders/geom.glsl (https://github.com/openframeworks/openFrameworks/blob/master/apps/examples/geometryShaderExample/bin/data/shaders/geom.glsl)

THE PROBLEM: the problem is that now my shader scale the width of the strip processing it segment by segment; the scaling is based on the length of the segment; but this approach cause a big eye gap between small and big segment.
To solve this I thought to do a little buffer with the last segment width and start the next segment and to do a little control at the first vertex to don't fall in error assigning it a width which doesn't exists.
It doesn't work.
I don't manage why, the control point always think we are at the first vertex. Is not a simple error I think, I checked also after a walk with the dog :) .

Here is the shader:



///////////////////////////////
// GLSL shaders
// PARAMETERS PASSED TO SHADERS
// float thickness default=0.1
// float limiter default=0.2
// vec3 lightDir default= 0.0 0.04 1.0
// line_strip vertices

////////////////
// VERTEX SHADER

#version 120

uniform float limiter;

void main(void)
{
// just bit waving
vec4 wave = vec4(gl_Vertex[0],gl_Vertex[1],gl_Vertex[2]*sin(gl_Vertex[0]),gl_Vertex[3]);
gl_FrontColor = gl_Color;
gl_Position = wave;
}
//////////////////
// GEOMETRY SHADER
// input type: GL_LINES
// output type: GL_TRIANGLE_STRIP
// vertices out: 4

/***********************************************
*
* Based on:
* Geometry shader to convert lines into triangle strips
* Memo Akten
* www.memo.tv

************************************************/

#version 120
#extension GL_EXT_geometry_shader4 : enable

uniform float thickness;
uniform vec3 lightDir;
uniform float limiter;

void main(void) {
// actual working vertices
vec3 p0;
vec3 p1;

vec3 dir; // normalized direction vector from p0 to p1

vec3 thick; // thick vector
vec3 oldthick; // old thick vector
float thickM; // thick modifier

vec3 norm;

// distance calculation stuff
vec2 P;
vec2 Q;

// color stuff
float fColMult;
vec4 colMult;


// loop stuff
int i;
bool first = true;

vec3 up = vec3(0, 0, 1); // arbitrary up vector

// go trought the vertices and do the transformation
for(i=0; i<gl_VerticesIn; i++){
if (first == true) { // maybe isn't a good way do a big control like this but is for debugging
first = false; // seems this doesn't work
// set working vertices
p0 = gl_PositionIn[i].xyz;
p1 = gl_PositionIn[i+1].xyz;

// some calculations
dir = normalize(p1 - p0);
thick = normalize(cross(dir, up));
norm = cross(thick, dir);

fColMult = abs(dot(norm, lightDir)); // simple lighting

P = vec2(p0[0],p0[1]);
Q = vec2(p1[0],p1[1]);
thickM = distance(P,Q)+0.02; // the lenght of the segment influeces his thickness

if (thickM > limiter) { // clipping
thickM = limiter;
}
thick *= thickness*thickM; // set calculated thickness

gl_Position = gl_ModelViewProjectionMatrix * vec4(p0 - thick, 1.0);
gl_FrontColor = vec4(gl_FrontColorIn[i].rgb * fColMult, 1.0);
EmitVertex();

gl_Position = gl_ModelViewProjectionMatrix * vec4(p0 + thick, 1.0);
gl_FrontColor = vec4(gl_FrontColorIn[i].rgb * fColMult, 1.0);
EmitVertex();

gl_Position = gl_ModelViewProjectionMatrix * vec4(p1 - thick, 1.0);
gl_FrontColor = vec4(gl_FrontColorIn[i+1].rgb * fColMult, 1.0);
EmitVertex();

gl_Position = gl_ModelViewProjectionMatrix * vec4(p1 + thick, 1.0);
gl_FrontColor = vec4(gl_FrontColorIn[i+1].rgb * fColMult, 1.0);
EmitVertex();

oldthick = thick;
} else {
p0 = gl_PositionIn[i].xyz;
p1 = gl_PositionIn[i+1].xyz;

dir = normalize(p1 - p0);
thick = normalize(cross(dir, up));
norm = cross(thick, dir);

fColMult = abs(dot(norm, lightDir)); // simple lighting

P = vec2(p0[0],p0[1]);
Q = vec2(p1[0],p1[1]);
thickM = distance(P,Q)+0.02; // the lenght of the segment influeces his thickness

if (thickM > limiter) { // clipping
thickM = limiter;
}
thick *= thickness*thickM; // set calculated thickness

gl_Position = gl_ModelViewProjectionMatrix * vec4(p0 - oldthick, 1.0);
//gl_FrontColor = gl_FrontColorIn[i] * fColMult;
gl_FrontColor = vec4(1.0,0.0,0.0,1.0); // if the is processed i surely see this
EmitVertex();

gl_Position = gl_ModelViewProjectionMatrix * vec4(p0 + oldthick, 1.0);
//gl_FrontColor = gl_FrontColorIn[i] * fColMult;
gl_FrontColor = vec4(1.0,0.0,0.0,1.0); // if the is processed i surely see this
EmitVertex();

gl_Position = gl_ModelViewProjectionMatrix * vec4(p1 - thick, 1.0);
//gl_FrontColor = gl_FrontColorIn[i+1] * fColMult;
gl_FrontColor = vec4(1.0,0.0,0.0,1.0); // if the is processed i surely see this
EmitVertex();

gl_Position = gl_ModelViewProjectionMatrix * vec4(p1 + thick, 1.0);
//gl_FrontColor = gl_FrontColorIn[i+1] * fColMult;
gl_FrontColor = vec4(1.0,0.0,0.0,1.0); // if the is processed i surely see this
EmitVertex();

oldthick = thick; // update the starting dimension
}
}
}

//////////////////
// FRAGMENT SHADER

void main (void) // do nothing
{
gl_FragColor = gl_Color;
}


What is wrong? This is my first approach to opengl and shading and I'm learning everything via web.
You are my masters.

Thank you for the attention.

esnho
10-07-2011, 04:54 PM
I've understood, I'm trying to do ham with carrots, right?

I'm in wrong because I didn't studied WHAT a geometry shader is. It can not recognize old segments or old variables. Is always refreshing the processing each segment.
RIGHT?

Please tell me that I'm a donkey.

And sorry for my English.

Alfonse Reinheart
10-07-2011, 07:23 PM
I'm in wrong because I didn't studied WHAT a geometry shader is. It can not recognize old segments or old variables. Is always refreshing the processing each segment.

What do you mean by that? A geometry shader operates on a single incoming primitive, just as a vertex shader operates on a single incoming vertex, and a fragment shader operates on a single incoming fragment. And the output values from a GS are made undefined after every Emit call, so you need to fill all of them in for every vertex you write.

malexander
10-10-2011, 11:03 AM
I'm in wrong because I didn't studied WHAT a geometry shader is. It can not recognize old segments or old variables. Is always refreshing the processing each segment.
If you're drawing a line strip with 10 segments and you draw these as a GL_LINE_STRIP, then each segment will be processed independently as a 2 vertex primitive.

If you were to draw the line strip as GL_LINE_STRIP_ADJACENCY, you will have 4 vertices available to you in the geometry shader. This will give you read access to the previous and next line segments' vertices while you process the current strip, though you won't have access to previously computed values. That should be enough to smoothly blend the segments together.

You'll need two extra vertices at the beginning and end of the strip for a line-adjacency primitive (12 total for a 10 segment line strip) which you can add by simply doubling the first and last vertex - 0,0,1,2,3,4,5,6,7,8,9,9. You can also linearly extrapolate the first and last vertex from the first and last line segments if that makes the geometry shader computation easier.

esnho
10-12-2011, 07:39 AM
Yes, is what I've understood, thank for confirmation.

The only thing I did not understood is this: if I declare a variable outside the main it is always made undefined after every main() execution?

malexander
10-13-2011, 02:59 PM
There are 3 variable declarations outside of main - uniforms, varying inputs and varying outputs. Uniforms will maintain their constant value, varying inputs will be filled with the new vertices to process, and varying outputs will be undefined.