Esempio n. 1
0
void Mesher::eval_zero_crossings(Vec3f* v0, Vec3f* v1, unsigned count)
{
    float p[count];
    for (unsigned i=0; i < count; ++i)
        p[i] = 0.5;

    float step = 0.25;

    Region dummy;
    dummy.X = ex;
    dummy.Y = ey;
    dummy.Z = ez;
    dummy.voxels = count;

    for (int iteration=0; iteration < 8; ++iteration)
    {
        // Load new data into the x, y, z arrays.
        for (unsigned i=0; i < count; i++)
        {
            dummy.X[i] = v0[i][0] * (1 - p[i]) + v1[i][0] * p[i];
            dummy.Y[i] = v0[i][1] * (1 - p[i]) + v1[i][1] * p[i];
            dummy.Z[i] = v0[i][2] * (1 - p[i]) + v1[i][2] * p[i];
        }
        float* out = eval_r(tree, dummy);

        for (unsigned i=0; i < count; i++)
            if      (out[i] < 0)    p[i] += step;
            else if (out[i] > 0)    p[i] -= step;

        step /= 2;
    }
}
Esempio n. 2
0
static
void region8(MathTree* tree, Region region, uint8_t** img)
{
    float *X = malloc(region.voxels*sizeof(float)),
          *Y = malloc(region.voxels*sizeof(float)),
          *Z = malloc(region.voxels*sizeof(float));

    // Copy the X, Y, Z vectors into a flattened matrix form.
    int q = 0;
    for (int k = region.nk - 1; k >= 0; --k) {
        for (int j = 0; j < region.nj; ++j) {
            for (int i = 0; i < region.ni; ++i) {
                X[q] = region.X[i];
                Y[q] = region.Y[j];
                Z[q] = region.Z[k];
                q++;
            }
        }
    }
    region.X = X;
    region.Y = Y;
    region.Z = Z;

    float* result = eval_r(tree, region);

    // Free the allocated matrices
    free(X);
    free(Y);
    free(Z);

    for (int k = region.nk - 1; k >= 0; --k) {
        uint8_t L = region.L[k+1] >> 8;

        for (int j = 0; j < region.nj; ++j) {
            int row = j + region.jmin;

            for (int i = 0; i < region.ni; ++i) {
                int col = i + region.imin;

               if (*(result++) < 0 && img[row][col] < L) {
                    img[row][col] = L;
                }
            }
        }
    }
}
Esempio n. 3
0
// Evaluates a region voxel-by-voxel, storing the output in the data
// member of the tristate struct.
bool Mesher::load_packed(const Region& r)
{
    // Only load the packed matrix if we have few enough voxels.
    const unsigned voxels = (r.ni+1) * (r.nj+1) * (r.nk+1);
    if (voxels >= MIN_VOLUME)
        return false;

    // We've already run interval evaluation for this region
    // (at the beginning of triangulate_region), so here we'll
    // just disable inactive nodes.
    disable_nodes(tree);

    // Flatten a 3D region into a 1D list of points that
    // touches every point in the region, one by one.
    int q = 0;
    for (unsigned k=0; k <= r.nk; ++k) {
        for (unsigned j=0; j <= r.nj; ++j) {
            for (unsigned i=0; i <= r.ni; ++i) {
                X[q] = r.X[i];
                Y[q] = r.Y[j];
                Z[q] = r.Z[k];
                q++;
            }
        }
    }

    // Make a dummy region that has the newly-flattened point arrays as the
    // X, Y, Z coordinate data arrays (so that we can run eval_r on it).
    packed.imin = r.imin;
    packed.jmin = r.jmin;
    packed.kmin = r.kmin;
    packed.ni = r.ni;
    packed.nj = r.nj;
    packed.nk = r.nk;
    packed.X = X;
    packed.Y = Y;
    packed.Z = Z;
    packed.voxels = voxels;

    // Run eval_r and copy the data out
    memcpy(data, eval_r(tree, packed), voxels * sizeof(float));
    has_data = true;

    return true;
}
Esempio n. 4
0
// Estimate the normals of a set of points.
std::list<Vec3f> Mesher::get_normals(const std::list<Vec3f>& points)
{
    // Find epsilon as the single shortest side length divided by 10.
    float epsilon = INFINITY;
    auto j = points.begin();
    j++;
    for (auto i = points.begin(); j != points.end(); ++i, ++j)
    {
        if (j != points.end())
        {
            auto d = *j - *i;
            epsilon = fmin(epsilon, d.norm() / 100.0f);
        }
    }

    // We'll be evaluating a dummy region to numerically estimate gradients
    Region dummy;
    dummy.voxels = points.size() * 7;
    if (dummy.voxels >= MIN_VOLUME)
        std::cerr << "Error: too many normals to calculate at once!"
                  << std::endl;
    dummy.X = nx;
    dummy.Y = ny;
    dummy.Z = nz;

    // Load position data into the dummy region
    int i=0;
    for (auto v : points)
    {
        dummy.X[i]   = v[0];
        dummy.X[i+1] = v[0] + epsilon;
        dummy.X[i+2] = v[0];
        dummy.X[i+3] = v[0];
        dummy.X[i+4] = v[0] - epsilon;
        dummy.X[i+5] = v[0];
        dummy.X[i+6] = v[0];

        dummy.Y[i]   = v[1];
        dummy.Y[i+1] = v[1];
        dummy.Y[i+2] = v[1] + epsilon;
        dummy.Y[i+3] = v[1];
        dummy.Y[i+4] = v[1];
        dummy.Y[i+5] = v[1] - epsilon;
        dummy.Y[i+6] = v[1];

        dummy.Z[i]   = v[2];
        dummy.Z[i+1] = v[2];
        dummy.Z[i+2] = v[2];
        dummy.Z[i+3] = v[2] + epsilon;
        dummy.Z[i+4] = v[2];
        dummy.Z[i+5] = v[2];
        dummy.Z[i+6] = v[2] - epsilon;
        i += 7;
    }

    float* out = eval_r(tree, dummy);

    // Extract normals from the evaluated data.
    std::list<Vec3f> normals;
    i = 0;
    for (auto v : points)
    {
        const float dx = (out[i+1] - out[i]) - (out[i+4] - out[i]);
        const float dy = (out[i+2] - out[i]) - (out[i+5] - out[i]);
        const float dz = (out[i+3] - out[i]) - (out[i+6] - out[i]);
        normals.push_back(Vec3f(dx, dy, dz).normalized());
        i += 7;
    }

    return normals;
}
Esempio n. 5
0
_STATIC_
void triangulate_voxel(MathTree* tree, const Region r,
                       float** const verts, unsigned* const count,
                       unsigned* const allocated,
                       Region packed, const float* data)
{
    // If we can calculate all of the points in this region with a single
    // eval_r call, then do so.  This large chunk will be used in future
    // recursive calls to make things more efficient.
    const unsigned voxels = (r.ni+1)*(r.nj+1)*(r.nk+1);
    if (!data && voxels < MIN_VOLUME)
    {
        packed = r;

        // Copy the X, Y, Z vectors into a flattened matrix form.
        packed.X = malloc(voxels*sizeof(float));
        packed.Y = malloc(voxels*sizeof(float));
        packed.Z = malloc(voxels*sizeof(float));

        int q = 0;
        for (int k = 0; k <= r.nk; ++k) {
            for (int j = 0; j <= r.nj; ++j) {
                for (int i = 0; i <= r.ni; ++i) {
                    packed.X[q] = r.X[i];
                    packed.Y[q] = r.Y[j];
                    packed.Z[q] = r.Z[k];
                    q++;
                }
            }
        }
        // Update the voxel count
        packed.voxels = voxels;

        data = eval_r(tree, packed);

        // Free the allocated matrices
        free(packed.X);
        free(packed.Y);
        free(packed.Z);
    }

    // If we have greater than one voxel, subdivide and recurse.
    if (r.voxels > 1)
    {
        Region octants[8];
        const uint8_t split = octsect(r, octants);
        for (int i=0; i < 8; ++i)
        {
            if (split & (1 << i))
            {
                triangulate_voxel(tree, octants[i],
                                  verts, count, allocated,
                                  packed, data);
            }
        }
        return;
    }

    // Find corner distance values for this voxel
    float d[8];
    for (int i=0; i < 8; ++i)
    {
        // Figure out where this bit of data lives in the larger eval_r array.
        const unsigned index =
            (r.imin - packed.imin + ((i & 4) ? r.ni : 0)) +
            (r.jmin - packed.jmin + ((i & 2) ? r.nj : 0))
                * (packed.ni+1) +
            (r.kmin - packed.kmin + ((i & 1) ? r.nk : 0))
                * (packed.ni+1) * (packed.nj+1);

        d[i] = data[index];
    }

    // Loop over the six tetrahedra that make up a voxel cell
    for (int t=0; t < 6; ++t)
    {
        // Find vertex positions for this tetrahedron
        uint8_t vertices[] = {0, 7, VERTEX_LOOP[t], VERTEX_LOOP[t+1]};

        // Figure out which of the sixteen possible combinations
        // we're currently experiencing.
        uint8_t lookup = 0;
        for (int v=3; v>=0; --v) {
            lookup = (lookup << 1) + (d[vertices[v]] < 0);
        }

        // Iterate over (up to) two triangles in this tetrahedron
        for (int i=0; i < 2; ++i)
        {
            if (EDGE_MAP[lookup][i][0][0] == -1)    break;

            // Do we need to allocate more space for incoming vertices?
            // If so, double the buffer size.
            if ((*count) + 9 >= (*allocated))
            {
                *allocated *= 2;
                *verts = realloc(*verts, sizeof(float)*(*allocated));
            }

            // ...and insert vertices into the mesh.
            for (int v=0; v < 3; ++v)
            {
                const Vec3f vertex = zero_crossing(d,
                        vertices[EDGE_MAP[lookup][i][v][0]],
                        vertices[EDGE_MAP[lookup][i][v][1]]);
                (*verts)[(*count)++] = vertex.x * (r.X[1] - r.X[0]) + r.X[0];
                (*verts)[(*count)++] = vertex.y * (r.Y[1] - r.Y[0]) + r.Y[0];
                (*verts)[(*count)++] = vertex.z * (r.Z[1] - r.Z[0]) + r.Z[0];
            }
        }
    }

}