// CS3451 Computer Graphics // P3 - Triangle Mesh // Catherine Herrington // http://www-static.cc.gatech.edu/grads/c/catyarr/Tmesh // Modified on June 15, 2006 // Triangle mesh viewer with support for corner table // Written by Jarek Rossignac June 2006 // OpenGL version //import processing.opengl.*; import javax.swing.JOptionPane; // VERTICES int w=6; // size of initial Tmesh-grid made in setup int nv = w*w, maxnv = 255;; // current and max number of vertices int nt = 2*(w-1)*(w-1), maxnt = maxnv*2; // current and max number of triangles pt[] G = new pt [maxnv]; // geometry table (vertices) float[][] UV = new float [maxnv][2]; // texture coordinates for the vertices vec[] Nv = new vec [maxnv]; // vectors associated with vertices for normal or laplace vec[] Nt = new vec [maxnt]; // vectors associated with triangles for normal int [] valence = new int [maxnv]; // valence (count of incident triangles) for the vertices pt Cbox = new pt(0,0,0); // box center float Rbox; // box radius int iMesh = 0; // toggle between mesh files to load int iNegHit = -1; int iEdgeHit = 0; int iPosHit = 1; int iNoHit = 2; int iTriHit = 1; int iNumViews = 200; //Number of views to use to determine edge importance int iPercentToShow = 5; //Percentage of Edges to display int iNumEdgesToShow = 0; //Number of important edges needed to show int iTotalNumEdges = 0; //Total number of edges int iMaxSilEdgeCnt = 0; //Maximum value of edge that is seen most as a silhouette vec labelD=new vec(-10,-10, 2); // offset vector for labels boolean bShowNormals =false; boolean bShowLabels = false; boolean bShowVertices = false; boolean bJumps = true; boolean bShowSilhouette = true; boolean bShowImportant = false; boolean bFillTriangles = true; boolean bVisibleSilhouettes = true; // CAMERA pt pOrigin=new pt(0,0,0); pt pEye=new pt(0,0,600); // point from where you picked cam C = new cam(pEye, pOrigin); cam C1 = new cam(pEye, pOrigin); cam C2 = new cam(pEye, pOrigin); pt pMark = new pt(0,0,0); // point you pick on mesh // CORNERS int nc = nt*3; // current number of corners int[] V = new int [3*maxnt]; // V table (triangle/vertex indices) int[] O = new int [3*maxnt]; // O table (opposite corner indices) int[] Edge = new int [3*maxnt]; // Edge table (Edge made by corner and opposite corner indices) int c = 0; // corner // GUI int bi=-1; // index of selected vertex, -1 if none selected color grey = color(200, 200, 210), red = color(200, 10, 10), blue = color(10, 10, 200), lightblue = color(150, 150, 255), green = color(10, 200, 20), black = color(10, 10, 10), magenta = color(250, 50, 100), brown = color(150, 100, 50), yellow = color(245, 238, 80), lightgreen = color(150, 255, 150), lightpink = color(255, 160, 160), lightpurple = color(220, 150, 220); void setup() { size(750, 750, P3D); //void setup() { size(750, 750, OPENGL); PFont font = loadFont("Courier-14.vlw"); textFont(font, 12); for (int i=0; i= iNumEdgesToShow) { i=3*nt; } //Exit if found enough edges } iSilValue--; //Search for lower silhouette hit values } }; boolean silhouetteEdge (pt pViewPoint, int c) { boolean bcCW, boCW; int o = o(c); //opposite of corner c bcCW = pViewPoint.cw(G[V[c]], G[V[n(c)]], G[V[p(c)]]); // Determines if the triangle containing corner c is // clockwise from the perspective of the ViewPoint boCW = pViewPoint.cw(G[V[o]], G[V[n(o)]], G[V[p(o)]]); // Determines if the triangle containing corner o is // clockwise from the perspective of the ViewPoint if(bcCW == boCW){return false;} //if the orientations are the same, then it is not a silhouette edge //Silhouette edge found, now see if it is visible if( bVisibleSilhouettes ) { // Can ignore "only visible" silhouette option by pressing 'v' pt pMidEdge = new pt(0,0,0); pMidEdge = midPt(g(p(c)), g(n(c))); //Point in middle of silhouette edge vec vViewToMid = new vec(0,0,0); vViewToMid = pViewPoint.vecTo(pMidEdge); float fNorm = vViewToMid.norm(); //Distance from middle of viewpoint to silhouette for(int j=0; j fDist ) { return false;} //If triangle is closer that the edges midpoint (behind) return false } } } } return true; //Visible silhouette edge is found } int rayHitTri(pt pViewPoint, pt pMidEdge, pt A, pt B, pt C) { boolean s = pViewPoint.cw(A,B,C); boolean sA = pViewPoint.cw(pMidEdge,B,C); boolean sB = pViewPoint.cw(A,pMidEdge,C); boolean sC = pViewPoint.cw(A,B,pMidEdge); if((s==sA) && (s==sB) && (s==sC)) { //Triangle is hit if all triangles forming tetrahedron are the same orientation if(s) {return 1;} else {return -1;}} //send back info as to whether it is cw or ccw else {return 0;} } float rayDistToTriPt(pt E, pt P, pt A, pt B, pt C) { vec EA = new vec(0,0,0); EA = E.vecTo(A); vec AB = new vec(0,0,0); AB = A.vecTo(B); vec AC = new vec(0,0,0); AC = A.vecTo(C); vec EP = new vec(0,0,0); EP = E.vecTo(P); vec EH = new vec(0,0,0); pt H = E.make(); float fDistPH = mixed(AB,AC,EA) / mixed(AB,AC,EP); //Determines distance to triangle H.addScaledVec(fDistPH,EP); EH = E.vecTo(H); return EH.norm(); } void computeImportantEdges() { iTotalNumEdges = 0; for (int i=0; i<3*nt; i++) { Edge[i]=0; //Reset Edge's importance if( i < o(i) ) { iTotalNumEdges++; } //Check edge only once for a corner and its opposite } iNumEdgesToShow = (iPercentToShow*iTotalNumEdges)/100; float fRadius = 2*Rbox; pt pViewArray = new pt(0,0,0); iMaxSilEdgeCnt = 0; for(int iView=0; iView iMaxSilEdgeCnt) {iMaxSilEdgeCnt = Edge[i];} //Keep track of the highest importance } } } } } void shade(int i) { beginShape(TRIANGLES); G[V[3*i]].vert(); G[V[3*i+1]].vert(); G[V[3*i+2]].vert(); endShape(); }; void computeO() { // works only if triangles are properly oriented for (int i=0; i<3*nt; i++) {O[i]=-1;}; for (int i=0; i<3*nt; i++) {for (int j=i+1; j<3*nt; j++) { if( (v(n(i))==v(p(j))) && (v(p(i))==v(n(j))) ) {O[i]=j; O[j]=i;}; };}; }; vec triNormal(int i) { return(triNormalFromPts(G[V[3*i]], G[V[3*i+1]], G[V[3*i+2]])); }; pt triCenter(int i) {return(triCenterFromPts( G[V[3*i]], G[V[3*i+1]], G[V[3*i+2]] )); }; void computeTriNormals() {for (int i=0; i2){iMesh=0;} c=0; if(iMesh==0){println("Load mesh.vts");} else {println("Load mesh"+iMesh+".vts"); } loadMesh(); computeBox(); C.F.setToPoint(Cbox); C.pullE(); orientTrianglesEdges(); computeO(); computeTriNormals(); computeImportantEdges(); }; if (key=='t') {println("t("+c+")="+t(c));}; if (key=='n') {println("n("+c+")="+n(c)); c=n(c);}; if (key=='p') {println("p("+c+")="+p(c)); c=p(c);}; if (key=='o') {println("o("+c+")="+o(c)); opposite(); jump();}; if (key=='l') {println("l("+c+")="+l(c)); left(); jump();} if (key=='r') {println("r("+c+")="+r(c)); right(); jump();} if (key=='N') {bShowNormals=!bShowNormals; if (bShowNormals) {computeTriNormals(); } } if (key=='L') {bShowLabels=!bShowLabels; } if (key=='J') {bJumps=!bJumps; }; if (key=='V') {bShowVertices=!bShowVertices; } if (key=='f') {bFillTriangles =! bFillTriangles;}; if (key=='v') {bVisibleSilhouettes=!bVisibleSilhouettes; } if (key=='z') {C.pose(); C.zoom(); C.pullE(); }; if (key=='O') {C.setcam(pEye, pOrigin); C.F.setToPoint(Cbox); C.pullE();} //Revert view close to original if (key=='s') {bShowSilhouette=!bShowSilhouette; } if (key=='I') {bShowImportant=!bShowImportant; } if (keyCode==DOWN) { //decrease the percentage of shown edges iPercentToShow -= 5; if(iPercentToShow<0 ){ iPercentToShow = 0; } println("Important Edges to Show: "+iPercentToShow+"%"); iNumEdgesToShow = (iPercentToShow*iTotalNumEdges)/100; } if (keyCode==UP) { //increase the percentage of shown edges iPercentToShow += 5; if(iPercentToShow>100){ iPercentToShow = 100; } println("Important Edges to Show: "+iPercentToShow+"%"); iNumEdgesToShow = (iPercentToShow*iTotalNumEdges)/100; } if (key=='%') { String strPercent = JOptionPane.showInputDialog(null, "Enter Percentage of Most Important Edges to Display:"); //Show dialog to enter % if(strPercent != null) { int iPrevious = iPercentToShow; iPercentToShow = Integer.parseInt(strPercent); if(iPercentToShow>100 || iPercentToShow<0 ){ iPercentToShow = iPrevious; } println("Important Edges to Show: "+iPercentToShow+"%"); iNumEdgesToShow = (iPercentToShow*iTotalNumEdges)/100; } } } void left() {if(l(c)!=-1) {c=l(c);}} //Find left corner if it exists void right() {if(r(c)!=-1) {c=r(c);}} //Find right corner if it exists void opposite() {if(o(c)!=-1) {c=o(c);}} //Find opposite corner if it exists void jump() {if (bJumps) {C.jump(c);}} //Jump to camera to corner if specified to jump void saveMesh() { String [] inppts = new String [nv+1+nt+1]; int s=0; inppts[s++]=str(nv); for (int i=0; i0)&&(fDepth