creates mesh interior and surface sample points and clusters them into particles
| 392 | |
| 393 | // creates mesh interior and surface sample points and clusters them into particles |
| 394 | void SampleMesh(const Vec3* vertices, int numVertices, const int* indices, int numIndices, float radius, float volumeSampling, float surfaceSampling, std::vector<Vec3>& outPositions) |
| 395 | { |
| 396 | Vec3 meshLower(FLT_MAX); |
| 397 | Vec3 meshUpper(-FLT_MAX); |
| 398 | |
| 399 | for (int i = 0; i < numVertices; ++i) |
| 400 | { |
| 401 | meshLower = Min(meshLower, vertices[i]); |
| 402 | meshUpper = Max(meshUpper, vertices[i]); |
| 403 | } |
| 404 | |
| 405 | std::vector<Vec3> samples; |
| 406 | |
| 407 | if (volumeSampling > 0.0f) |
| 408 | { |
| 409 | // recompute expanded edges |
| 410 | Vec3 edges = meshUpper - meshLower; |
| 411 | |
| 412 | // use a higher resolution voxelization as a basis for the particle decomposition |
| 413 | float spacing = radius / volumeSampling; |
| 414 | |
| 415 | // tweak spacing to avoid edge cases for particles laying on the boundary |
| 416 | // just covers the case where an edge is a whole multiple of the spacing. |
| 417 | float spacingEps = spacing*(1.0f - 1e-4f); |
| 418 | |
| 419 | // make sure to have at least one particle in each dimension |
| 420 | int dx, dy, dz; |
| 421 | dx = spacing > edges.x ? 1 : int(edges.x / spacingEps); |
| 422 | dy = spacing > edges.y ? 1 : int(edges.y / spacingEps); |
| 423 | dz = spacing > edges.z ? 1 : int(edges.z / spacingEps); |
| 424 | |
| 425 | int maxDim = max(max(dx, dy), dz); |
| 426 | |
| 427 | // expand border by two voxels to ensure adequate sampling at edges |
| 428 | meshLower -= 2.0f*Vec3(spacing); |
| 429 | meshUpper += 2.0f*Vec3(spacing); |
| 430 | maxDim += 4; |
| 431 | |
| 432 | vector<uint32_t> voxels(maxDim*maxDim*maxDim); |
| 433 | |
| 434 | // we shift the voxelization bounds so that the voxel centers |
| 435 | // lie symmetrically to the center of the object. this reduces the |
| 436 | // chance of missing features, and also better aligns the particles |
| 437 | // with the mesh |
| 438 | Vec3 meshOffset; |
| 439 | meshOffset.x = 0.5f * (spacing - (edges.x - (dx - 1)*spacing)); |
| 440 | meshOffset.y = 0.5f * (spacing - (edges.y - (dy - 1)*spacing)); |
| 441 | meshOffset.z = 0.5f * (spacing - (edges.z - (dz - 1)*spacing)); |
| 442 | meshLower -= meshOffset; |
| 443 | |
| 444 | Voxelize((const float*)vertices, numVertices, indices, numIndices, maxDim, maxDim, maxDim, &voxels[0], meshLower, meshLower + Vec3(maxDim*spacing)); |
| 445 | |
| 446 | // sample interior |
| 447 | for (int x = 0; x < maxDim; ++x) |
| 448 | { |
| 449 | for (int y = 0; y < maxDim; ++y) |
| 450 | { |
| 451 | for (int z = 0; z < maxDim; ++z) |
no test coverage detected