JOGL>Pipe
Pipe
Geometry
The pipe is described by three cubic Bezier functions, and the drawing is made using Frenet Frames [2] .
The main pipeshape is described with an axis in YZ-plane, and the ovals describing the thickness along the main outline is described with two Beziers, one for X and one for Y.
_init
bezier bezierZ=new bezier( new v3d(1f,4.0f,0f), new v3d(1f,-4.5f,2.5f), new v3d(1f,8.5f,3.5f), new v3d(1f,6.0f,8.0f)); bezier bezierX=new bezier( new v3d(1.5f,0f,0f), new v3d(2.1f,0f,0f), new v3d(0.4f,0f,0f), new v3d(0.3f,0f,0f)); bezier bezierY=new bezier( new v3d(0f,1.5f,0f), new v3d(0f,2.1f,0f), new v3d(0f,0.4f,0f), new v3d(0f,0.1f,0f));
v3d is a simple utility class for handling vectors, crossproduct, matrixmultiplication etc.
The bezierfunctions are handled with a simple class:
_bezier.java
package pipe; /** * Handling a Bezier function and its derivative * @author bs */ public class bezier { v3d p0,p1,p2,p3; public bezier(v3d P0,v3d P1,v3d P2,v3d P3) { p0=P0;p1=P1;p2=P2;p3=P3; } /** * Calculate a position for a given parameter t [0..1] * @param t The parameter t * @return A point as a vector */ public v3d B(float t){ return new v3d( p0.x*(-t*t*t + 3*t*t - 3*t + 1)+ p1.x*(3*t*t*t - 6*t*t + 3*t)+ p2.x*(-3*t*t*t + 3*t*t)+ p3.x*(t*t*t), p0.y*(-t*t*t + 3*t*t - 3*t + 1)+ p1.y*(3*t*t*t - 6*t*t + 3*t)+ p2.y*(-3*t*t*t + 3*t*t)+ p3.y*(t*t*t), p0.z*(-t*t*t + 3*t*t - 3*t + 1)+ p1.z*(3*t*t*t - 6*t*t + 3*t)+ p2.z*(-3*t*t*t + 3*t*t)+ p3.z*(t*t*t)); } /** * Calculate a value of the derivative for a given parameter t [0..1] * @param t The parameter t * @return A vector */ public v3d dB(float t){ return new v3d( p0.x*(-3*t*t + 6*t - 3)+ p1.x*(9*t*t - 12*t + 3)+ p2.x*(-9*t*t + 6*t)+ p3.x*(3*t*t), p0.y*(-3*t*t + 6*t - 3)+ p1.y*(9*t*t - 12*t + 3)+ p2.y*(-9*t*t + 6*t)+ p3.y*(3*t*t), p0.z*(-3*t*t + 6*t - 3)+ p1.z*(9*t*t - 12*t + 3)+ p2.z*(-9*t*t + 6*t)+ p3.z*(3*t*t)); } }
The points and the normals on the pipebody is calculated as Frenet Frames. The method that generates the pipeshape is:
_construct
BUF=FloatBuffer.allocate((RCOUNT+2)*(ZCOUNT+2)*3); NBUF=FloatBuffer.allocate((RCOUNT+2)*(ZCOUNT+2)*3); BUF.rewind(); NBUF.rewind(); float bigt=0.0f; // all bands along the pipebody for(int zix=0;zix<ZCOUNT;zix++) { // where is it v3d C=bezierZ.B(bigt); // finding the normalized tangent // here in yz-plane v3d Z=bezierZ.dB(bigt).normalize(); // finding a second vector, use x v3d X=new v3d(1.0f,0.0f,0.0f).normalize(); // finding a third vector v3d Y=Z.cross(X).normalize(); // setting up the matix that will take us to the // Frenet frame located at this t-point // M=|X,Y,Z,C|, where C is the Bezier itself // note transpose of matrix float M[]={ X.x,X.y,X.z,0, Y.x,Y.y,Y.z,0, Z.x,Z.y,Z.z,0, C.x,C.y,C.z,1}; // do the ellipse float v=0.0f; v3d xp=bezierX.B(bigt); v3d yp=bezierY.B(bigt); // doing the ellipse for(int vix=0;vix <= RCOUNT;vix++) { float xv=(float)(xp.x*Math.cos(v)); float yv=(float)(yp.y*Math.sin(v)); v3d p=new v3d(xv,yv,0).matmult(M); //points BUF.put(p.x); BUF.put(p.y); BUF.put(p.z); // generate normals NBUF.put(p.x-C.x); NBUF.put(p.y-C.y); NBUF.put(p.z-C.z); v+=rstep; } bigt+=zstep; }
We use the buffered data to draw the shape
_draw
BUF.rewind(); NBUF.rewind(); int roundCount=RCOUNT+1; setBrownMaterial(gl); gl.glBegin(GL.GL_QUAD_STRIP); int offset=0; for(int zix=1;zix < BROWNCOUNT; zix++) { offset=roundCount*zix*3; for(int rix=0;rix <roundCount;rix++) { gl.glNormal3fv(NBUF.array(), offset-roundCount*3+(rix)*3); gl.glVertex3fv(BUF.array(), offset-roundCount*3+(rix)*3); gl.glNormal3fv(NBUF.array(), offset+rix*3); gl.glVertex3fv(BUF.array(), offset+rix*3); } } gl.glEnd(); setBrassMaterial(gl); gl.glBegin(GL.GL_QUAD_STRIP); for(int zix=BROWNCOUNT-1;zix < BRASSCOUNT;zix++) { offset=roundCount*zix*3; for(int rix=0;rix <roundCount;rix++) { gl.glNormal3fv(NBUF.array(), offset-roundCount*3+(rix)*3); gl.glVertex3fv(BUF.array(), offset-roundCount*3+(rix)*3); gl.glNormal3fv(NBUF.array(), offset+rix*3); gl.glVertex3fv(BUF.array(), offset+rix*3); } } gl.glEnd(); setBlackMaterial(gl); gl.glBegin(GL.GL_QUAD_STRIP); for(int zix=BRASSCOUNT;zix < ZCOUNT;zix++) { offset=roundCount*zix*3; for(int rix=0;rix <roundCount;rix++) { gl.glNormal3fv(NBUF.array(), offset-roundCount*3+(rix)*3); gl.glVertex3fv(BUF.array(), offset-roundCount*3+(rix)*3); gl.glNormal3fv(NBUF.array(), offset+rix*3); gl.glVertex3fv(BUF.array(), offset+rix*3); } } gl.glEnd();