void ofxMarchingCubes::update(float _threshold, bool bCalcNormals){ threshold = _threshold; numTriangles = 0; vertices.clear(); normals.clear(); int numPointsX = gridResX-1;; int numPointsY = gridResY-1; int numPointsZ = gridResZ-1; for(unsigned int i=0; i<numPointsX; ++i){ for(unsigned int j=0; j<numPointsY; ++j){ for(unsigned int k=0; k<numPointsZ; ++k){ polygonise(i, j, k, bCalcNormals); } } } }
std::vector<Primitive *> Particles::getSurfacePrims(double isolevel, double fStepSize, BSDF* bsdf) { std::vector<Primitive *> prims; double xmin = getParticlesAxisMin(0); double ymin = getParticlesAxisMin(1); double zmin = getParticlesAxisMin(2); double xmax = getParticlesAxisMax(0); double ymax = getParticlesAxisMax(1); double zmax = getParticlesAxisMax(2); int xsteps = (int)((xmax-xmin)/fStepSize); int ysteps = (int)((ymax-ymin)/fStepSize); int zsteps = (int)((zmax-zmin)/fStepSize); vector<vector<Index> > polygons; vector<Vector3D> vertexPositions; for (int ix = 0; ix <= xsteps; ix++) for (int iy = 0; iy <= ysteps; iy++) for (int iz = 0; iz <= zsteps; iz++) { double x1 = xmin+ix*fStepSize; double x2 = std::min(xmax, x1+fStepSize); double y1 = ymin+iy*fStepSize; double y2 = std::min(ymax, y1+fStepSize); double z1 = zmin+iz*fStepSize; double z2 = std::min(zmax, z1+fStepSize); GridCell grid = generateGridCell(x1,x2,y1,y2,z1,z2); std::vector<TriangleVertices *> triangles = polygonise(grid, isolevel); for (int i=0; i<triangles.size(); i++) { Vector3D p1 = triangles[i]->p[0]; Vector3D p2 = triangles[i]->p[1]; Vector3D p3 = triangles[i]->p[2]; Vector3D n1 = getVertexNormal(p1); Vector3D n2 = getVertexNormal(p2); Vector3D n3 = getVertexNormal(p3); MarchingTriangle *tri = new MarchingTriangle(p1, p2, p3, n1, n2, n3, bsdf); prims.push_back(tri); } } return prims; }
/** Uses modified marching cubes algorithm */ int Dataset::calculate_surface() { Gridcell grid; int index, in, i,j,k; int num_triangles = 0, new_triangles = 0, *buffer_count; buffer_count = (int*) malloc(sizeof(int)*num_grains); if (buffer_count == NULL) { return 0; } double sa = 0, AB[3], AC[3], ABAC; Triangle *t; bool already_marked; // For each grain allocate initial buffer and set surface count to zero //-------------------------------------------------- for(i=0;i<num_grains;i++){ if (grains[i].surface_triangles != NULL) { free(grains[i].surface_triangles); } grains[i].surface_triangles = (Triangle*) malloc(sizeof(Triangle)*TRIANGLE_BUFFER); if (grains[i].surface_triangles == NULL) { return 0; } grains[i].num_triangles = 0; buffer_count[i] = 1; } XYZ pi; int present[9]; int num_present; present[0] = -1; // Cycle through each 'cube' in dataset and calculate the surface for // each of the grains present in the cube. //-------------------------------------------------- for(index=0;index<nv;index++){ if (index%1000 == 0) { //#pragma omp critial(display) progress_callback((float)index / nv,"Calculating surfaces", false); } pi.x = (index % tx)-1; pi.y = (index/dy % ty)-1; pi.z = (index/dz % tz)-1; num_present = 1; for(j=0;j<8;j++) { grid.p[j].x = pi.x + grid_offset[j][X]; grid.p[j].y = pi.y + grid_offset[j][Y]; grid.p[j].z = pi.z + grid_offset[j][Z]; if (grid.p[j].x<0 || grid.p[j].y<0 || grid.p[j].z<0 || grid.p[j].x>=(tx-2) || grid.p[j].y>=(ty-2) || grid.p[j].z>=(tz-2)) { grid.grain[j] = -1; } else { in = index - dz + grid_offset[j][X] + grid_offset[j][Y]*dy + grid_offset[j][Z]*dz; grid.grain[j] = data[in].grain; // Keep track of which grains are present //-------------------------------------------------- if (data[in].grain >= 0) { already_marked = false; for(k=0;k<num_present;k++){ if (data[in].grain == present[k]) { already_marked = true; } } if (!already_marked) { present[ num_present++ ] = data[in].grain; } } } } for(j=1;j<num_present;j++){ num_triangles = grains[ present[j] ].num_triangles; // Make sure there's enough space in the buffer //-------------------------------------------------- if(num_triangles+12 > buffer_count[ present[j] ]*TRIANGLE_BUFFER) { grains[ present[j] ].surface_triangles = (Triangle*) realloc(grains[ present[j] ].surface_triangles, sizeof(Triangle)*(++buffer_count[present[j]])*TRIANGLE_BUFFER); if (grains[ present[j] ].surface_triangles == NULL) { return 0; } } new_triangles = polygonise(grid, present[j], grains[ present[j] ].surface_triangles+num_triangles); grains[ present[j] ].num_triangles += new_triangles; } } for(i=0;i<num_grains;i++){ sa = 0; t = grains[i].surface_triangles; // Calculate surface area of grains //-------------------------------------------------- for(j=0;j<grains[i].num_triangles;j++){ AB[X] = (t->p[0].x - t->p[1].x)*(double)steps[X]; AB[Y] = (t->p[0].y - t->p[1].y)*(double)steps[Y]; AB[Z] = (t->p[0].z - t->p[1].z)*(double)steps[Z]; AC[X] = (t->p[0].x - t->p[2].x)*(double)steps[X]; AC[Y] = (t->p[0].y - t->p[2].y)*(double)steps[Y]; AC[Z] = (t->p[0].z - t->p[2].z)*(double)steps[Z]; ABAC = AB[X]*AC[X]+AB[Y]*AC[Y]+AB[Z]*AC[Z]; sa += 0.5 * sqrt( (AB[X]*AB[X] + AB[Y]*AB[Y] + AB[Z]*AB[Z])* (AC[X]*AC[X] + AC[Y]*AC[Y] + AC[Z]*AC[Z])- ABAC*ABAC ); t++; } grains[i].surface_area = (float) sa; } free(buffer_count); progress_callback(1,"Calculating grain surfaces", false); }
//-------------------------------------------------------------------------------------------------- /// Generate surface representation of the specified cut plane /// /// \note Will compute normals before returning geometry //-------------------------------------------------------------------------------------------------- void StructGridCutPlane::computeCutPlane() { DebugTimer tim("StructGridCutPlane::computeCutPlane", DebugTimer::DISABLED); bool doMapScalar = false; if (m_mapScalarSetIndex != UNDEFINED_UINT && m_scalarMapper.notNull()) { doMapScalar = true; } uint cellCountI = m_grid->cellCountI(); uint cellCountJ = m_grid->cellCountJ(); uint cellCountK = m_grid->cellCountK(); // Clear any current data m_vertices.clear(); m_vertexScalars.clear(); m_triangleIndices.clear(); m_meshLineIndices.clear(); // The indexing conventions for vertices and // edges used in the algorithm: // edg verts // 4-------------5 *------4------* 0 0 - 1 // /| /| /| /| 1 1 - 2 // / | / | 7/ | 5/ | 2 2 - 3 // / | / | |z / 8 / 9 3 3 - 0 // 7-------------6 | | /y *------6------* | 4 4 - 5 // | | | | |/ | | | | 5 5 - 6 // | 0---------|---1 *---x | *------0--|---* 6 6 - 7 // | / | / 11 / 10 / 7 7 - 4 // | / | / | /3 | /1 8 0 - 4 // |/ |/ |/ |/ 9 1 - 5 // 3-------------2 *------2------* 10 2 - 6 // vertex indices edge indices 11 3 - 7 // uint k; for (k = 0; k < cellCountK; k++) { uint j; for (j = 0; j < cellCountJ; j++) { uint i; for (i = 0; i < cellCountI; i++) { size_t cellIndex = m_grid->cellIndexFromIJK(i, j, k); Vec3d minCoord; Vec3d maxCoord; m_grid->cellMinMaxCordinates(cellIndex, &minCoord, &maxCoord); // Early reject for cells outside clipping box if (m_clippingBoundingBox.isValid()) { BoundingBox cellBB(minCoord, maxCoord); if (!m_clippingBoundingBox.intersects(cellBB)) { continue; } } // Check if plane intersects this cell and skip if it doesn't if (!isCellIntersectedByPlane(m_plane, minCoord, maxCoord)) { continue; } GridCell cell; bool isClipped = false; if (m_clippingBoundingBox.isValid()) { if (!m_clippingBoundingBox.contains(minCoord) || !m_clippingBoundingBox.contains(maxCoord)) { isClipped = true; minCoord.x() = CVF_MAX(minCoord.x(), m_clippingBoundingBox.min().x()); minCoord.y() = CVF_MAX(minCoord.y(), m_clippingBoundingBox.min().y()); minCoord.z() = CVF_MAX(minCoord.z(), m_clippingBoundingBox.min().z()); maxCoord.x() = CVF_MIN(maxCoord.x(), m_clippingBoundingBox.max().x()); maxCoord.y() = CVF_MIN(maxCoord.y(), m_clippingBoundingBox.max().y()); maxCoord.z() = CVF_MIN(maxCoord.z(), m_clippingBoundingBox.max().z()); } } cell.p[0].set(minCoord.x(), maxCoord.y(), minCoord.z()); cell.p[1].set(maxCoord.x(), maxCoord.y(), minCoord.z()); cell.p[2].set(maxCoord.x(), minCoord.y(), minCoord.z()); cell.p[3].set(minCoord.x(), minCoord.y(), minCoord.z()); cell.p[4].set(minCoord.x(), maxCoord.y(), maxCoord.z()); cell.p[5].set(maxCoord.x(), maxCoord.y(), maxCoord.z()); cell.p[6].set(maxCoord.x(), minCoord.y(), maxCoord.z()); cell.p[7].set(minCoord.x(), minCoord.y(), maxCoord.z()); // Fetch scalar values double cellScalarValue = 0; if (doMapScalar) { cellScalarValue = m_grid->cellScalar(m_mapScalarSetIndex, i, j, k); // If we're doing node averaging we must populate grid cell with scalar values interpolated to the grid points if (m_mapNodeAveragedScalars) { if (isClipped) { double scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[0], &scalarVal)) cell.s[0] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[1], &scalarVal)) cell.s[1] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[2], &scalarVal)) cell.s[2] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[3], &scalarVal)) cell.s[3] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[4], &scalarVal)) cell.s[4] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[5], &scalarVal)) cell.s[5] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[6], &scalarVal)) cell.s[6] = scalarVal; if (m_grid->pointScalar(m_mapScalarSetIndex, cell.p[7], &scalarVal)) cell.s[7] = scalarVal; } else { cell.s[0] = m_grid->gridPointScalar(m_mapScalarSetIndex, i, j + 1, k); cell.s[1] = m_grid->gridPointScalar(m_mapScalarSetIndex, i + 1, j + 1, k); cell.s[2] = m_grid->gridPointScalar(m_mapScalarSetIndex, i + 1, j, k); cell.s[3] = m_grid->gridPointScalar(m_mapScalarSetIndex, i, j, k); cell.s[4] = m_grid->gridPointScalar(m_mapScalarSetIndex, i, j + 1, k + 1); cell.s[5] = m_grid->gridPointScalar(m_mapScalarSetIndex, i + 1, j + 1, k + 1); cell.s[6] = m_grid->gridPointScalar(m_mapScalarSetIndex, i + 1, j, k + 1); cell.s[7] = m_grid->gridPointScalar(m_mapScalarSetIndex, i, j, k + 1); } } } Triangles triangles; uint numTriangles = polygonise(m_plane, cell, &triangles); if (numTriangles > 0) { // Add all the referenced vertices // At the same time registering their index in the 'global' vertex list uint globalVertexIndices[12]; int iv; for (iv = 0; iv < 12; iv++) { if (triangles.usedVertices[iv]) { globalVertexIndices[iv] = static_cast<uint>(m_vertices.size()); m_vertices.push_back(Vec3f(triangles.vertices[iv])); if (doMapScalar) { if (m_mapNodeAveragedScalars) { m_vertexScalars.push_back(triangles.scalars[iv]); } else { m_vertexScalars.push_back(cellScalarValue); } } } else { globalVertexIndices[iv] = UNDEFINED_UINT; } } // Build triangles from the cell const size_t prevNumTriangleIndices = m_triangleIndices.size(); uint t; for (t = 0; t < numTriangles; t++) { m_triangleIndices.push_back(globalVertexIndices[triangles.triangleIndices[3*t]]); m_triangleIndices.push_back(globalVertexIndices[triangles.triangleIndices[3*t + 1]]); m_triangleIndices.push_back(globalVertexIndices[triangles.triangleIndices[3*t + 2]]); } // Add mesh line indices addMeshLineIndices(&m_triangleIndices[prevNumTriangleIndices], numTriangles); } } } } //Trace::show("Vertices:%d TriConns:%d Tris:%d", m_vertices.size(), m_triangleIndices.size(), m_triangleIndices.size()/3); tim.reportTimeMS(); }
void render() { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); zviewpointSetupView(); const int MAX_TRIS = 1000000; static Triangle tris[MAX_TRIS]; int triCount = 0; const int steps = 60; const float stepsf = (float)steps; Rod r0( FVec3(-0.3f,0.f,0.f), FVec3(+0.f,0.f,0.f), Cloud_r ); Rod r1( FVec3(0.f,0.f,0.f), FVec3(0.2f,0.5f,0.f), Cloud_r ); Sphere s0( FVec3(-.5f, -.5f, 0.f), 0.25f ); Surface *surfaces[] = { (Surface *)&r0, (Surface *)&r1, (Surface *)&s0 }; int surfacesCount = sizeof(surfaces) / sizeof(surfaces[0]); float f[steps][steps][steps]; for( int xi=0; xi<steps; xi++ ) { for( int yi=0; yi<steps; yi++ ) { for( int zi=0; zi<steps; zi++ ) { FVec3 p( 2.f*(float)xi/stepsf-1.f, 2.f*(float)yi/stepsf-1.f, 2.f*(float)zi/stepsf-1.f ); f[xi][yi][zi] = 0.f; for( int i=0; i<surfacesCount; i++ ) { f[xi][yi][zi] += surfaces[i]->surface( p ); } } } } for( int xi=0; xi<steps-1; xi++ ) { for( int yi=0; yi<steps-1; yi++ ) { for( int zi=0; zi<steps-1; zi++ ) { GridCell g; float x0 = 2.f*(float)(xi+0)/stepsf-1.f; float x1 = 2.f*(float)(xi+1)/stepsf-1.f; float y0 = 2.f*(float)(yi+0)/stepsf-1.f; float y1 = 2.f*(float)(yi+1)/stepsf-1.f; float z0 = 2.f*(float)(zi+0)/stepsf-1.f; float z1 = 2.f*(float)(zi+1)/stepsf-1.f; g.p[0] = FVec3( x0, y0, z0 ); g.p[1] = FVec3( x1, y0, z0 ); g.p[2] = FVec3( x1, y1, z0 ); g.p[3] = FVec3( x0, y1, z0 ); g.p[4] = FVec3( x0, y0, z1 ); g.p[5] = FVec3( x1, y0, z1 ); g.p[6] = FVec3( x1, y1, z1 ); g.p[7] = FVec3( x0, y1, z1 ); g.val[0] = f[xi+0][yi+0][zi+0]; g.val[1] = f[xi+1][yi+0][zi+0]; g.val[2] = f[xi+1][yi+1][zi+0]; g.val[3] = f[xi+0][yi+1][zi+0]; g.val[4] = f[xi+0][yi+0][zi+1]; g.val[5] = f[xi+1][yi+0][zi+1]; g.val[6] = f[xi+1][yi+1][zi+1]; g.val[7] = f[xi+0][yi+1][zi+1]; triCount += polygonise( g, Cloud_r, &tris[triCount] ); assert( triCount < MAX_TRIS ); } } } DiscWarp dw( FVec3(-0.2f,0.f,0.f), FVec3(1.f,0.f,0.f) ); for( int i=0; i<triCount; i++ ) { tris[i].p[0] = dw.warp( tris[i].p[0] ); tris[i].p[1] = dw.warp( tris[i].p[1] ); tris[i].p[2] = dw.warp( tris[i].p[2] ); } dw.draw(); static unsigned int triList[MAX_TRIS*3]; static FVec3 normals[MAX_TRIS*3]; ZGLLight light0; light0.resetToDefaults(); light0.active = 1; light0.ambient[0] = 0.05f; light0.ambient[1] = 0.05f; light0.ambient[2] = 0.05f; light0.diffuse[0] = 0.8f; light0.diffuse[1] = 0.2f; light0.diffuse[2] = 0.2f; light0.dir[0] = 10.f; light0.dir[1] = 0.f; light0.dir[2] = 0.f; light0.makeDirectional(); light0.setLightNumber( 0 ); ZGLLight light1; light1.resetToDefaults(); light1.active = 1; light1.ambient[0] = 0.05f; light1.ambient[1] = 0.05f; light1.ambient[2] = 0.05f; light1.diffuse[0] = 0.2f; light1.diffuse[1] = 0.2f; light1.diffuse[2] = 0.8f; light1.dir[0] = -10.f; light1.dir[1] = -10.f; light1.dir[2] = 0.f; light1.makeDirectional(); light1.setLightNumber( 1 ); glEnable( GL_COLOR_MATERIAL ); glEnable( GL_LIGHTING ); glEnable( GL_LIGHT0 ); glEnable( GL_LIGHT1 ); glEnable( GL_DEPTH_TEST ); glEnable( GL_NORMALIZE ); light0.setGL(); light1.setGL(); for( int i=0; i<triCount; i++ ) { FVec3 d10( tris[i].p[1] ); d10.sub( tris[i].p[0] ); FVec3 d20( tris[i].p[2] ); d20.sub( tris[i].p[0] ); normals[i*3+0] = d20; normals[i*3+0].cross( d10 ); FVec3 d01( tris[i].p[0] ); d01.sub( tris[i].p[1] ); FVec3 d21( tris[i].p[2] ); d21.sub( tris[i].p[1] ); normals[i*3+1] = d01; normals[i*3+1].cross( d21 ); FVec3 d02( tris[i].p[0] ); d02.sub( tris[i].p[2] ); FVec3 d12( tris[i].p[1] ); d12.sub( tris[i].p[2] ); normals[i*3+2] = d12; normals[i*3+2].cross( d02 ); triList[i*3+0] = i*3+0; triList[i*3+1] = i*3+1; triList[i*3+2] = i*3+2; } glColor3ub( 255, 255, 255 ); glEnableClientState( GL_VERTEX_ARRAY ); glVertexPointer( 3, GL_FLOAT, 0, &tris[0] ); glEnableClientState( GL_NORMAL_ARRAY ); glNormalPointer( GL_FLOAT, 0, &normals[0] ); glDrawElements( GL_TRIANGLES, triCount*3, GL_UNSIGNED_INT, &triList[0] ); }