//http://www.packtpub.com/sites/default/files/9781849518048_Chapter_07.pdf //knotExample void ofApp::addCircle( ofVec3f nextPoint, ofMesh &mesh ){ float time = ofGetElapsedTimef(); //Time //Parameters – twisting and rotating angles and color ofFloatColor color( ofNoise( time * 0.05 ), ofNoise( time * 0.1 ), ofNoise( time * 0.15 )); color.setSaturation( 1.0 ); //Make the color maximally //Add vertices for (int i=0; i<circleN; i++) { float angle = float(i) / circleN * TWO_PI+(PI*0.25); float x = Rad * cos( angle ); float y = Rad * sin( angle ); ofPoint p = nextPoint+ofVec3f(x ,y , 0); mesh.addVertex( p ); mesh.addColor( color ); } //Add the triangles int base = mesh.getNumVertices() - 2 * circleN; if ( base >= 0 ) { //Check if it is not the first step //and we really need to add the triangles for (int i=0; i<circleN; i++) { int a = base + i; int b = base + (i + 1) % circleN; int c = circleN + a; int d = circleN + b; mesh.addTriangle(a,b,d); mesh.addTriangle(a, d, c); } //Update the normals setNormals( mesh ); } }
void BGGraphics::pushCirclePart(ofMesh& mesh, ofVec2f position, float nodeRadius, float minAngle, float deltaAngle) { mesh.setMode(OF_PRIMITIVE_TRIANGLES); pushVertex(mesh, position.x, position.y, 1, 0, 0, 1, 0, 0); float innerRadius = nodeRadius - NETWORK_OFFSET; float internalOffsetY = .5;// innerRadius / nodeRadius; int samples = (int)(15 * deltaAngle / M_PI); samples = max(1, samples); for(int i=0; i<samples; ++i) { float angle = minAngle + deltaAngle * i / (float)(samples - 1); ofVec2f to(cosf(angle), sinf(angle)); ofVec2f p1 = position + to * innerRadius; ofVec2f p2 = position + to * nodeRadius; //pushVertex(ofMesh & mesh, float x, float y, float z, float nx, float ny, float nz, float offsetX, float offsetY) pushVertex(mesh, p1.x, p1.y, 1, 0, 0, 1, 0, internalOffsetY); pushVertex(mesh, p2.x, p2.y, 0, to.x, to.y, 0, 0, 1); if(i > 0) { int offset = 1 + 2 * i; mesh.addTriangle(0, offset - 2, offset); mesh.addTriangle(offset - 2, offset - 1, offset); mesh.addTriangle(offset - 1, offset, offset + 1); } } }
void MeshHelper::fuseNeighbours( ofMesh& outputMesh, const ofMesh& sourceMesh, float fuseDistance ) { //@todo tex coords, normals assert( sourceMesh.getMode() == OF_PRIMITIVE_TRIANGLES ); if ( fuseDistance < 0 ) { // fuse close-enough vertices // first define 'close enough' as 1/10000 of smallest dimension of the bounding box width/height/depth ofVec3f tlb, brf; // top left back, bottom right front calculateAABoundingBox( sourceMesh, tlb, brf ); float minDimension = min(brf.x-tlb.x,min(brf.y-tlb.y, brf.z-tlb.z)); fuseDistance = minDimension * 0.00001f; } // now fuse map<int,int> fused; vector<ofVec3f> vertices; for ( int i=0; i<sourceMesh.getNumVertices(); i++ ) { const ofVec3f& vertex = sourceMesh.getVertex(i); //vertex.rotate(10, 10, 10); bool didFuse = false; for ( int j=0; j<vertices.size(); j++ ) { if ( (vertex-vertices[j]).length()<fuseDistance ) { // fuse i to j fused[i] = j; didFuse = true; break; } } if ( !didFuse ) { vertices.push_back( vertex ); fused[i] = vertices.size()-1; } } // build the output mesh outputMesh.clear(); outputMesh.addVertices(vertices); if ( sourceMesh.getNumIndices() > 0 ) { // walk through indices to build up the new mesh const vector<ofIndexType>& indices = sourceMesh.getIndices(); for ( int i=0; i<indices.size(); i+=3 ) { assert( fused.find( indices[i] ) != fused.end() ); assert( fused.find( indices[i+1] ) != fused.end() ); assert( fused.find( indices[i+2] ) != fused.end() ); outputMesh.addTriangle( fused[indices[i]], fused[indices[i+1]], fused[indices[i+2]] ); } } else { // triangles are just triples of vertices for ( int i=0; i<sourceMesh.getNumVertices(); i+=3 ) { outputMesh.addTriangle( fused[i], fused[i+1], fused[i+2] ); } } ofLogNotice("MeshHelper") << "fuseNeighbours: input " << sourceMesh.getNumVertices() << " vertices/" << sourceMesh.getNumIndices() << " indices, output " << outputMesh.getNumVertices() << " vertices/" << outputMesh.getNumIndices() << " indices"; }
void BGGraphics::pushDoubleConnectedNode(ofMesh& mesh, ofVec2f position, ofVec2f startEdgePoint, ofVec2f endEdgePoint) { int samples = 10; for(int i=0; i<samples; ++i) { float t = i / (float)(samples - 1); float localDepth = -.5 + t; ofVec2f pt, normal; sampleSpline(startEdgePoint, position, endEdgePoint, t, pt, normal); pushVertex(mesh, pt.x + NETWORK_OFFSET * normal.x, pt.y + NETWORK_OFFSET * normal.y, 0, normal.x, normal.y, 0, localDepth, 1); pushVertex(mesh, pt.x, pt.y, 1, 0, 0, 1, localDepth, 0); pushVertex(mesh, pt.x - NETWORK_OFFSET * normal.x, pt.y - NETWORK_OFFSET * normal.y, 0, -normal.x, -normal.y, 0, localDepth, 1); if(i > 0) { int offset = 3 * i; for(int j=0; j<2; ++j) { mesh.addTriangle(offset + j, offset - 3 + j, offset - 2 + j); mesh.addTriangle(offset + j, offset + 1 + j, offset - 2 + j); } } } }
void getCellMesh(voro::voronoicell &_c, ofPoint _pos, ofMesh& mesh ){ if( _c.p ) { ofPoint centroid = getCellCentroid(_c,_pos); int i,j,k,l,m,n; // Vertex // double *ptsp=_c.pts; vector<ofPoint> vertices; vector<ofPoint> normals; for(i = 0; i < _c.p; i++, ptsp+=3){ ofPoint newPoint; newPoint.x = _pos.x + ptsp[0]*0.5; newPoint.y = _pos.y + ptsp[1]*0.5; newPoint.z = _pos.z + ptsp[2]*0.5; vertices.push_back(newPoint); ofPoint newNormal; newNormal = _pos - newPoint;//centroid ; newNormal = newNormal.normalize(); normals.push_back(newNormal); } // ofMesh mesh; mesh.setMode(OF_PRIMITIVE_TRIANGLES ); mesh.addVertices(vertices); mesh.addNormals(normals); // Index // for(i = 1; i < _c.p; i++){ for(j = 0; j < _c.nu[i]; j++) { k = _c.ed[i][j]; if( k >= 0 ) { _c.ed[i][j]=-1-k; l = _c.cycle_up( _c.ed[i][ _c.nu[i]+j], k); m = _c.ed[k][l]; _c.ed[k][l]=-1-m; while(m!=i) { n = _c.cycle_up( _c.ed[k][ _c.nu[k]+l],m); mesh.addTriangle(i, k, m); k=m; l=n; m=_c.ed[k][l]; _c.ed[k][l]=-1-m; } } } } // return mesh; } // return ofMesh(); };
void BGGraphics::pushSingleConnectedNode(ofMesh& mesh, ofVec2f position, float nodeRadius, ofVec2f edgePoint, bool isRoot) { float innerRadius = nodeRadius - NETWORK_OFFSET; ofVec2f to = edgePoint - position; float toDist = to.length(); to /= toDist; ofVec2f perp = ofVec2f(-to.y, to.x); float depthFactor = isRoot ? .5 : -.5; float proj = sqrtf(.5 * innerRadius * innerRadius); if(toDist > innerRadius + NETWORK_OFFSET) { float offset = min(innerRadius + .5f * (toDist - innerRadius), 2 * proj); //perform spline traversal... ofVec2f controlPoint = position + offset * to;// .5 * (position + innerRadius * to) + .5 * edgePoint; float angle = acosf(innerRadius / offset); pushCirclePart(mesh, position, nodeRadius, atan2f(to.y, to.x) + angle, 2 * (M_PI - angle)); int splineOffset = mesh.getVertices().size(); /* ofVec2f anchorLeft = position + proj * to + proj * perp; ofVec2f anchorRight = position + proj * to - proj * perp; ofVec2f toA1 = (anchorLeft - position).normalize(); ofVec2f toA2 = (anchorRight - position).normalize(); */ float toAng = atan2f(to.y, to.x); ofVec2f toA1(cosf(toAng + angle), sinf(toAng + angle)); ofVec2f toA2(cosf(toAng - angle), sinf(toAng - angle)); float facU = innerRadius * cosf(angle); float facV = innerRadius * sinf(angle); float anchorProj = sqrtf(.5 * innerRadius * innerRadius); ofVec2f anchorLeft = position + innerRadius * toA1; ofVec2f anchorRight = position + innerRadius * toA2; float innerRadiusFactor = .5;// innerRadius / nodeRadius; //add first point: pushVertex(mesh, anchorLeft.x + NETWORK_OFFSET * toA1.x, anchorLeft.y + NETWORK_OFFSET * toA1.y, 0, toA1.x, toA1.y, 0, 0, 1); pushVertex(mesh, anchorLeft.x, anchorLeft.y, 1, 0, 0, 1, 0, innerRadiusFactor); pushVertex(mesh, position.x, position.y, 1, 0, 0, 1, 0, 0); pushVertex(mesh, anchorRight.x, anchorRight.y, 1, 0, 0, 1, 0, innerRadiusFactor); pushVertex(mesh, anchorRight.x + NETWORK_OFFSET * toA2.x, anchorRight.y + NETWORK_OFFSET * toA2.y, 0, toA2.x, toA2.y, 0, 0, 1); int samples = 8; for(int i=1; i<samples; ++i) { float t = i / (float)(samples - 1); float localDepth = depthFactor * t; ofVec2f pt, normal; sampleSpline(anchorLeft, controlPoint, edgePoint, t, pt, normal); normal = -normal; /* //project point on skeleton: //float projDistance = dot(pt - position, to); float innerSampleOffset = dot(pt - position, to);//(pt - centerSample).length(); ofVec2f centerSample = position + innerSampleOffset * to; float centerSampleDepth = depth + depthFactor * (innerSampleOffset / toDist); centerSampleDepth = (centerSampleDepth + localDepth) * .5; */ ofVec2f centerSample; getIntersection(position, to, pt, normal, centerSample); //float innerSampleOffset = (pt - centerSample).length(); float innerSampleOffsetFactor = (1 - t) * .5;// innerSampleOffset / (innerSampleOffset + NETWORK_OFFSET); ofVec2f otherPt = position + reflect(pt - position, to); ofVec2f otherNormal = reflect(normal, to); pushVertex(mesh, pt.x + NETWORK_OFFSET * normal.x, pt.y + NETWORK_OFFSET * normal.y, 0, normal.x, normal.y, 0, localDepth, 1); pushVertex(mesh, pt.x, pt.y, 1, 0, 0, 1, localDepth, innerSampleOffsetFactor); pushVertex(mesh, centerSample.x, centerSample.y, 1, 0, 0, 1, localDepth, 0); pushVertex(mesh, otherPt.x, otherPt.y, 1, 0, 0, 1, localDepth, innerSampleOffsetFactor); pushVertex(mesh, otherPt.x + NETWORK_OFFSET * otherNormal.x, otherPt.y + NETWORK_OFFSET * otherNormal.y, 0, otherNormal.x, otherNormal.y, 0, localDepth, 1); if(i > 0) { int offset = splineOffset + 5 * i; for(int j=0; j<4; ++j) { mesh.addTriangle(offset + j, offset - 5 + j, offset - 4 + j); mesh.addTriangle(offset + j, offset + 1 + j, offset - 4 + j); } } } } else pushSeparateNode(mesh, position, nodeRadius); }
void BGGraphics::pushTripleConnectedNode(ofMesh& mesh, ofVec2f position, ofVec2f startEdgePoint, ofVec2f endEdgePoint1, ofVec2f endEdgePoint2) { ofVec2f orderedPts[3] = { startEdgePoint, endEdgePoint1, endEdgePoint2 }; /* ofMesh centerTriangleMesh; centerTriangleMesh.setMode(OF_PRIMITIVE_TRIANGLE_FAN); ofVec2f centerTriangleTexPt = calculateInternalTexOffset(0.5, true, true, -1); pushVertex(centerTriangleMesh, position.x, position.y, 1, 0, 0, 1, centerTriangleTexPt.x, centerTriangleTexPt.y); */ ofVec2f sumCenterPosition(0,0); int centerIndices[9]; int halfSamples = 8; for(int idx=0; idx<3; ++idx) { int prevIdx = idx == 0 ? 2 : (idx - 1); int nextIdx = (idx + 1) % 3; //ofVec2f focus1 = focusPts[idx]; //ofVec2f focus2 = focusPts[prevIdx]; for(int i=0; i<halfSamples; ++i) { float t = .5 * i / (float)(halfSamples - 1); ofVec2f pt1, normal1, pt2, normal2; sampleSpline(orderedPts[idx], position, orderedPts[nextIdx], t, pt1, normal1); sampleSpline(orderedPts[idx], position, orderedPts[prevIdx], t, pt2, normal2); normal2 = -normal2; ofVec2f center = (pt1 + pt2) / 2.0; /* float offAngle1 = focusAngles[idx] + t * deltaAngle; ofVec2f offVector1 = ofVec2f(cosf(offAngle1), sinf(offAngle1)); float offAngle2 = focusAngles[prevIdx] + (1. - t) * deltaAngle; ofVec2f offVector2 = ofVec2f(cosf(offAngle2), sinf(offAngle2)); */ //ofVec2f BGGraphics::calculateInternalTexOffset(float t, bool isSourceSpline, int offsetIndex) bool isSourceSegment = idx == 0; bool isSourceSpline1 = true, isSourceSpline2 = true; float t1 = t, t2 = t; if(idx == 1) { isSourceSpline1 = false; t2 = 1. - t; } else if(idx == 2) { //mirrored version of idx == 1 isSourceSpline2 = false; t1 = 1. - t; } ofVec2f centerTexPt = calculateInternalTexOffset(t1, isSourceSpline1, isSourceSegment, 0); ofVec2f innerTexPt1 = calculateInternalTexOffset(t1, isSourceSpline1, isSourceSegment, 1); ofVec2f outerTexPt1 = calculateInternalTexOffset(t1, isSourceSpline1, isSourceSegment, 2); ofVec2f innerTexPt2 = calculateInternalTexOffset(t2, isSourceSpline2, isSourceSegment, 1); ofVec2f outerTexPt2 = calculateInternalTexOffset(t2, isSourceSpline2, isSourceSegment, 2); //TODO: remove!! //centerTexPt = (innerTexPt1 + innerTexPt2) / 2.0; //innerTexPt2 = ofVec2f(-10000,-10000); //outerTexPt2 = innerTexPt2; /* ofVec2f innerTexPt1 = focus1 + baseSize * offVector1; ofVec2f outerTexPt1 = focus1 + .5 * baseSize * offVector1; ofVec2f innerTexPt2 = focus2 + baseSize * offVector2; ofVec2f outerTexPt2 = focus2 + .5 * baseSize * offVector2; ofVec2f centerTexPt = (innerTexPt1 + innerTexPt2) / 2.0; */ pushVertex(mesh, pt1.x + NETWORK_OFFSET * normal1.x, pt1.y + NETWORK_OFFSET * normal1.y, 0, normal1.x, normal1.y, 0, outerTexPt1.x, outerTexPt1.y); pushVertex(mesh, pt1.x, pt1.y, 1, 0, 0, 1, innerTexPt1.x, innerTexPt1.y); pushVertex(mesh, center.x, center.y, 1, 0, 0, 1, centerTexPt.x, centerTexPt.y); pushVertex(mesh, pt2.x, pt2.y, 1, 0, 0, 1, innerTexPt2.x, innerTexPt2.y); pushVertex(mesh, pt2.x + NETWORK_OFFSET * normal2.x, pt2.y + NETWORK_OFFSET * normal2.y, 0, normal2.x, normal2.y, 0, outerTexPt2.x, outerTexPt2.y); if(i > 0) { int offset = (5 * idx * halfSamples) + 5 * i; for(int j=0; j<4; ++j) { mesh.addTriangle(offset + j, offset - 5 + j, offset - 4 + j); mesh.addTriangle(offset + j, offset + 1 + j, offset - 4 + j); } if(i == halfSamples - 1) { sumCenterPosition += pt1; for(int j=0; j<3; ++j) { centerIndices[3 * idx + j] = offset + 1 + j; } } } } } //add center point: ofVec2f avgCenter = sumCenterPosition / 3.0; ofVec2f centerTriangleTexPt = calculateInternalTexOffset(0.5, true, true, -1); pushVertex(mesh, avgCenter.x, avgCenter.y, 1, 0, 0, 1, centerTriangleTexPt.x, centerTriangleTexPt.y); //stitch to bounds: int centerOffset = mesh.getVertices().size() - 1; for(int i=0; i<9; ++i) mesh.addTriangle(centerOffset, centerIndices[i], centerIndices[(i + 1) % 9]); //centerTriangleMesh.setVertex(0, ofVec3f(avgCenter.x, avgCenter.y, 1)); /* ofVec2f avgCenter = sumCenterPosition / 3.0; centerTriangleMesh.setVertex(0, ofVec3f(avgCenter.x, avgCenter.y, 1)); //stitch up center triangle fan: centerTriangleMesh.addVertex(centerTriangleMesh.getVertex(1)); centerTriangleMesh.addTexCoord(centerTriangleMesh.getTexCoord(1)); centerTriangleMesh.addNormal(centerTriangleMesh.getNormal(1)); centerTriangleMesh.addColor(centerTriangleMesh.getColor(1)); drawMesh(centerTriangleMesh, depth); */ }