Created
December 13, 2011 22:17
-
-
Save anselm/1474156 to your computer and use it in GitHub Desktop.
A snippet of code to draw opengl ribbons given a series of connected line segments
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Note that I wrote this in java in Processing - paste this GIST into processing to see it in action. | |
// It is not the most elegant thing ever but it does deal with end caps and ribbon loops and the like. | |
// If you port this over to say objective-c / opengl / c etc - you may need to deal with polygon direction | |
// here is a snapshot of it running : http://www.flickr.com/photos/anselmhook/6507471719/in/photostream | |
int nvertices = 0; | |
float[] vertexpool = new float[3000]; | |
float x1,x2,y1,y2; | |
void intersect(int kind, float x0, float y0, float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4) { | |
float det = ((y4-y3)*(x2-x1)-(x4-x3)*(y2-y1)); | |
if(det!=0) { | |
float ua = ((x4-x3)*(y1-y3)-(y4-y3)*(x1-x3))/det; | |
// float ub = ((x2-x1)*(y1-y3)-(y2-y1)*(x1-x3))/((y4-y3)*(x2-x1)-(x4-x3)*(y2-y1)); | |
float x = x1 + ua*(x2-x1); | |
float y = y1 + ua*(y2-y1); | |
if(ua < 0 || ua > 1) { | |
if(kind == 3) { | |
// segments don't meet up soon enough; so pick a compromise between their ends | |
vertexpool[nvertices] = x2+(x3-x2)/2; nvertices++; | |
vertexpool[nvertices] = y2+(y3-y2)/2; nvertices++; | |
} else { | |
// an alternative is to put a non pointy cap onto the end rather than hacking it | |
vertexpool[nvertices] = x2; nvertices++; | |
vertexpool[nvertices] = y2; nvertices++; | |
vertexpool[nvertices] = x3; nvertices++; | |
vertexpool[nvertices] = y3; nvertices++; | |
} | |
} else { | |
vertexpool[nvertices] = x; nvertices++; | |
vertexpool[nvertices] = y; nvertices++; | |
} | |
} else { | |
// the lines are parallel... so just take the input end points | |
vertexpool[nvertices] = x0; nvertices++; | |
vertexpool[nvertices] = y0; nvertices++; | |
} | |
} | |
void ribbonAddVertex(float distance, float x3, float y3, int kind) { | |
if(kind==0) { | |
// begin saving up vertices of the line | |
x1 = x3; | |
y1 = y3; | |
return; | |
} | |
if(kind==1) { | |
// continue building up an understanding of the line | |
x2 = x3; | |
y2 = y3; | |
return; | |
} | |
if(kind>=2) { | |
// there are enough vertices at this time to add another ribbon segment | |
// for debugging - let's see the ribbon center | |
// stroke(random(155),random(200),random(255)); | |
// line(x1,y1,x2,y2); | |
// line(x2,y2,x3,y3); | |
// get a perpendicular to this ribbon segment | |
float len1 = (float)Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)); | |
float nx1 = (x2-x1)/len1*distance; | |
float ny1 = (y2-y1)/len1*distance; | |
// get a perpendicular to the next ribbon segment | |
float len2 = (float)Math.sqrt((x3-x2)*(x3-x2)+(y3-y2)*(y3-y2)); | |
float nx2 = (x3-x2)/len2*distance; | |
float ny2 = (y3-y2)/len2*distance; | |
// define 4 line segments; for the current segment and next segment ribbon edges | |
distance = distance / 6; | |
float xa1 = x1-ny1 - nx1*distance; | |
float ya1 = y1+nx1 - ny1*distance; | |
float xa2 = x1+ny1 - nx1*distance; | |
float ya2 = y1-nx1 - ny1*distance; | |
float xb1 = x2-ny1 + nx1*distance; | |
float yb1 = y2+nx1 + ny1*distance; | |
float xb2 = x2+ny1 + nx1*distance; | |
float yb2 = y2-nx1 + ny1*distance; | |
float xc1 = x2-ny2 - nx2*distance; | |
float yc1 = y2+nx2 - ny2*distance; | |
float xc2 = x2+ny2 - nx2*distance; | |
float yc2 = y2-nx2 - ny2*distance; | |
float xd1 = x3-ny2 + nx2*distance; | |
float yd1 = y3+nx2 + ny2*distance; | |
float xd2 = x3+ny2 + nx2*distance; | |
float yd2 = y3-nx2 + ny2*distance; | |
if(kind == 2) { | |
// the caller has asked for a cap on the start of the ribbon - give them one | |
vertexpool[nvertices] = xa1; nvertices++; | |
vertexpool[nvertices] = ya1; nvertices++; | |
vertexpool[nvertices] = xa2; nvertices++; | |
vertexpool[nvertices] = ya2; nvertices++; | |
} | |
// add segment intersection marking ribbon edge between the two skeleton lines | |
// an alternative way would be a function like atan2(slope1)+atan2(slope2) * distance | |
intersect(kind, x2-ny1,y2+nx1, xa1,ya1,xb1,yb1, xc1,yc1,xd1,yd1); | |
intersect(kind, x2+ny1,y2-nx1, xa2,ya2,xb2,yb2, xc2,yc2,xd2,yd2); | |
if(kind == 9) { | |
// the caller has asked for a cap on the end of the ribbon - give them one | |
vertexpool[nvertices] = xd1; nvertices++; | |
vertexpool[nvertices] = yd1; nvertices++; | |
vertexpool[nvertices] = xd2; nvertices++; | |
vertexpool[nvertices] = yd2; nvertices++; | |
} | |
// save previous ribbon skeleton line for next round | |
x1 = x2; y1 = y2; | |
x2 = x3; y2 = y3; | |
return; | |
} | |
} | |
void setup() { | |
size(400, 400); | |
background(0); | |
stroke(153); | |
nvertices = 0; | |
float d = 10; | |
// these two vertices begin the line but no triangles are added yet; marked as starts | |
ribbonAddVertex(d,50,100,0); | |
ribbonAddVertex(d,100,100,1); | |
// these vertices make up the body of the ribbon | |
ribbonAddVertex(d,100,50,3); | |
ribbonAddVertex(d,200,30,3); | |
ribbonAddVertex(d,220,60,4); | |
ribbonAddVertex(d,280,130,4); | |
ribbonAddVertex(d,300,200,4); | |
ribbonAddVertex(d,290,300,4); | |
ribbonAddVertex(d,280,200,4); | |
ribbonAddVertex(d,100,200,4); | |
ribbonAddVertex(d,50,200,3); | |
ribbonAddVertex(d,50,160,3); | |
ribbonAddVertex(d,50,120,3); | |
// these vertices repeat the beginning but with enough data to close the ribbon as a loop | |
ribbonAddVertex(d,50,100,3); | |
ribbonAddVertex(d,100,100,3); | |
ribbonAddVertex(d,100,50,3); | |
// let us see the ribbon | |
for(int i = 0; i <=nvertices-6; i+=2) { | |
float x1 = vertexpool[i+0]; | |
float y1 = vertexpool[i+1]; | |
float x2 = vertexpool[i+2]; | |
float y2 = vertexpool[i+3]; | |
float x3 = vertexpool[i+4]; | |
float y3 = vertexpool[i+5]; | |
stroke(0,200,200); | |
line(x1,y1,x2,y2); | |
line(x1,y1,x3,y3); | |
line(x3,y3,x2,y2); | |
} | |
} | |
void draw() { | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment