PDA

View Full Version : Offset line

raziza
09-19-2011, 12:53 AM
I'm using VBO to draw a 1,000,000 points line strip.

I need to draw the line in black and two red lines as borders (I've attached example image file).

Is there a way to manipulate the matrices or do any other thing to draw the borders ?

AleaIactaEst
09-19-2011, 03:52 AM
This looks like all you need to do is to translate the red border lines, so all you need to do is to multiply the model matrix by a translation matrix.

raziza
09-19-2011, 08:36 AM
If you will check again the image, you will notice that the red border lines are not just offset from the black line,

They are kind of longer\shorter on the corners depends which side is the border.

MaxH
09-19-2011, 10:38 AM
How about simply drawing the line 3 times at different widths (using glLineWidth). Draw a fat, red, line, then a medium width white line, followed by a narrow black line. Turn Z buffering off and draw them on top of each other using the same set of vertices. No math necessary.

raziza
09-19-2011, 11:55 PM
I thought about it already. but the case is that i need to see what is behind the lines.. if i will draw wider main (black) line it will block what is behind it.

To make it simple for understand (or harder to implement - i guess) - i need to draw just the red lines. between the lines should be nothing.

any more suggestions ?

AleaIactaEst
09-20-2011, 05:24 AM
Imagnine there is a 'normal vector' at every vertex at the black line. You could translate every corresponding vertex of the red lines along this normal, which should yield the result you want.

If you are able to calculate all normals so that they all point in approximately the same direction (i.e. all pointing downwards or all pointing upwards) it should be easy generating the vertices for the border lines.

Calculating the 'normal' probably works like that: (I didn't test it)

-Choose a vertex
-Calculate 2 vectors describing the direction of the two adjacent lines
-find the largest angle alpha in between them (if both are 180 degrees choose one randomly)
-Create the normal by rotating it alpha/2.0 degrees
-If the normal is pointing upwards negate it (or do the opposite, negate all normals pointing downwards, doesn't matter)

-Repeat for all other vertices

You need some other solution for the leftmost and rightmost vertices of course, maybe by simply setting the normal to (0.0, 1.0) or (0.0, -1.0) or calculating a normal orthogonal to the only line that's connected with this vertex (which is probably the better solution)

_arts_
09-20-2011, 05:28 AM
What about just scaling them up and down ? If the origin is at the center of the black line, it should be possible. Add a little translation and you'll have this.

raziza
09-20-2011, 07:01 AM
First of all, Thanks for the answers.
But, :)

_arts_, if you will see, you will realize that its not simply scaling and transforming issue.. the vertexes are supposed to grow and shrink depends on the angle created by the two lines its connected to.

AleaIactaEst, The thing is that i don't want to calculate it all the time. I'm drawing complex lines with complex styles. and do that will cause lots of pre-calculations and time of loading.
But, i will try to write a vertex shader, and using the vertex attributes.

Correct me if i got you wrong

AleaIactaEst
09-20-2011, 08:09 AM
You got me right, i though calculating the vertices of the border lines on the cpu once will be fine. But even if your lines are changing dynamically, if 99% of your vertices stay the same from one frame to the next, you'll still be able to calculate the border lines efficient on the cpu, by updating only the relevant parts.

The very same algorithm could also be implemented in the vertex shader of course, which is probably the best solution if the vertices change very often.

raziza
09-20-2011, 09:04 AM
Great..

I will try it out and let you know.

Thanks man

MaxH
09-20-2011, 01:24 PM
Here's a solution that requires no math, but you must draw your line 4 times. It uses the depth buffer to 'mask' out the middle portion of a thick red line. The depth mask is created by drawing a thinner version of the same line first. I also draw points at the vertices to clean up the joints where the lines come together. Comment out the point drawing and you'll see what I mean. I'm sure this same approach could be done more elegantly, maybe using stencil planes. I'm more comfortable using the depth buffer.

void Hollow_Lines (void)
{
short v;
static float Line[5][2] = {{-1,-1},{-0.5,0.5},{1,-1.5},{2.5,-1},{3.5,.5}};

glEnable (GL_DEPTH_TEST);

glEnable (GL_BLEND );
glEnable (GL_LINE_SMOOTH );
glEnable (GL_POINT_SMOOTH );
glHint (GL_LINE_SMOOTH_HINT, GL_NICEST );
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

// Write 'invisible' thin version of line into into depth buffer only.

glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // Disables RGBA

glLineWidth (4.0);
glPointSize (3.0);

glPushMatrix ();
glTranslatef (0,0,0.001); // Puts thin line if 'front' of thick line.
glBegin (GL_LINE_STRIP);
for (v = 0; v < 5; v++) glVertex2fv (Line[v]);
glEnd ();
glBegin (GL_POINTS);
for (v = 0; v < 5; v++) glVertex2fv (Line[v]);
glEnd ();
glPopMatrix();

// Write visible, thick, red, version of line.

glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // Enable RGBA

glLineWidth (10.0);
glColor3f (1.0, 0.2, 0.2);
glBegin (GL_LINE_STRIP);
for (v = 0; v < 5; v++) glVertex2fv (Line[v]);
glEnd ();

glPointSize (10.0); // Use points at each vertex to clean up joints.
glColor3f (1.0, 0.2, 0.2);
glBegin (GL_POINTS);
for (v = 1; v < 4; v++) glVertex2fv (Line[v]);
glEnd (); // Try 0 and 5 here to put nice ends on the lines.
}

http://www.mfwweb.com/OpenGL/Hollow_Line.jpg

raziza
10-11-2011, 10:05 AM
Found time for it today.

First wrote code in CPU to make it work. I used the vectors of the next and previous segments, found to middle vector.

calculate the length of the vector for finding the new corner point. and boom its working.

Then, made a shader that do that. Used the vertex attribute for getting the previous and the next vectors (attribute.xy = previous, attribute.zw = Next) - working in 2D.

and it is working great and fast..