protected void Awake()
    {
        Application.targetFrameRate = 60;

        // create metaballs
        _metaballs = new Metaball[numberOfBalls];
        int i = 0;

        for (; i < numberOfBalls; ++i)
        {
            _metaballs[i] = new Metaball(new Vector3(Random.Range(bounds.min.x, bounds.max.x),
                                                     Random.Range(bounds.min.y, bounds.max.y), 0));
        }

        // create grid, used for caching samples and position lookups
        int   c = 0, r = 0, cols = Mathf.FloorToInt(gridResolution.x), rows = Mathf.FloorToInt(gridResolution.y);
        float xstep = bounds.size.x / gridResolution.x;
        float x = bounds.xMin, y = bounds.yMin;

        _gridSize = xstep * 0.5f;
        _grid     = new GridSample[cols * rows];

        while (c < cols)
        {
            r = 0;
            y = bounds.yMin;

            while (r < rows)
            {
                GridSample g = new GridSample(x, y);
                i    = (r * cols) + c;
                g.iB = c + 1 >= cols ? i : (r * cols) + (c + 1);
                g.iC = r + 1 >= rows ? i : ((r + 1) * cols) + (c);
                g.iD = c + 1 >= cols || r + 1 >= rows ? i : ((r + 1) * cols) + (c + 1);

                _grid[(r * cols) + c] = g;

                ++r;

                y += xstep;
            }

            ++c;
            x += xstep;
        }

        // create mesh and vertex/triangle buffers
        _verticesLength  = cols * rows * 4;
        _trianglesLength = _verticesLength;
        _vertices        = new Vector3[_verticesLength];
        _triangles       = new int[_trianglesLength];

        _mesh = new Mesh();
        _mesh.MarkDynamic();

        GetComponent <MeshFilter>().mesh = _mesh;
    }
Ejemplo n.º 2
0
    GridSample GetSample(Vector2 pos)
    {
        GridData   data = head;
        GridSample sample;

        sample.rot   = Quaternion.AngleAxis(0, Vector3.up);
        sample.scale = Vector3.one;
        int sampleCount = 0;

        while (true)
        {
            Vector2    vec         = data.pos - pos;
            GridSample sampledData = SampleData(data, vec);

            sample.rot    = sample.rot * sampledData.rot;
            sample.scale += sampledData.scale;

            ++sampleCount;
            // is a subgrid?
            if (data.subGrid0 == null)
            {
                break;
            }

            // find correct sub grid
            if (Inside(data.subGrid0.pos, data.subGrid0.halfWidth, pos))
            {
                data = data.subGrid0;
            }
            else if (Inside(data.subGrid1.pos, data.subGrid1.halfWidth, pos))
            {
                data = data.subGrid1;
            }
            else if (Inside(data.subGrid2.pos, data.subGrid2.halfWidth, pos))
            {
                data = data.subGrid2;
            }
            else if (Inside(data.subGrid3.pos, data.subGrid3.halfWidth, pos))
            {
                data = data.subGrid3;
            }
            else
            {
                break;
            }
        }

        // get average scale
        sample.scale /= sampleCount;

        return(sample);
    }
    private void SampleFunction(GridSample grid)
    {
        float z = 0;
        int   i = 0;

        for (; i < numberOfBalls; ++i)
        {
            Metaball ball = _metaballs[i];
            float    x2   = grid.x - ball.position.x;
            float    y2   = grid.y - ball.position.y;

            z += (ball.radius * ball.radius) / ((x2 * x2) + (y2 * y2));
        }

        grid.sample = z;
    }
    protected void Update()
    {
        // update ball positions
        int i = 0;

        for (; i < numberOfBalls; ++i)
        {
            Metaball ball = _metaballs[i];
            ball.position += ball.velocity * Time.deltaTime;

            if (ball.position.x > bounds.xMax || ball.position.x < bounds.xMin)
            {
                ball.velocity.x = -ball.velocity.x;
            }
            if (ball.position.y > bounds.yMax || ball.position.y < bounds.yMin)
            {
                ball.velocity.y = -ball.velocity.y;
            }
        }

        // update grid samples for new metaball positions
        int l = _grid.Length;

        for (i = 0; i < l; ++i)
        {
            SampleFunction(_grid[i]);
        }

        // build mesh from grid samples
        int vi = 0, ti = 0;

        for (i = 0; i < l; ++i)
        {
            GridSample grid = _grid[i];

            float sampleA = grid.sample;
            float sampleB = _grid[grid.iB].sample;
            float sampleC = _grid[grid.iC].sample;
            float sampleD = _grid[grid.iD].sample;

            // get the index value for this grid position
            int index = IndexFunction(sampleA, sampleB, sampleD, sampleC);
            if (index > 0 && index < 15)
            {
                // populate vertext and triangle buffers for this grid position
                Vector3 p = new Vector3(grid.x, grid.y, 0);

                Vector3[] points = MetaballDefs.pointLookupTable[index];
                int[]     triangles = MetaballDefs.triangleLookupTable[index];
                int       j = 0, k = triangles.Length;
                for (j = 0; j < k; j += 3)
                {
                    int t1 = triangles[j];
                    int t2 = triangles[j + 1];
                    int t3 = triangles[j + 2];

                    Vector3 p0 = points[t1];
                    Vector3 p1 = points[t2];
                    Vector3 p2 = points[t3];

                    // use SmoothFunction to Lerp points based on sample values
                    p0 = SmoothFunction(p0, sampleA, sampleB, sampleC, sampleD);
                    p1 = SmoothFunction(p1, sampleA, sampleB, sampleC, sampleD);
                    p2 = SmoothFunction(p2, sampleA, sampleB, sampleC, sampleD);

                    _vertices[vi]     = p + (p0 * _gridSize);
                    _vertices[vi + 1] = p + (p1 * _gridSize);
                    _vertices[vi + 2] = p + (p2 * _gridSize);

                    _triangles[ti]     = vi;
                    _triangles[ti + 1] = vi + 1;
                    _triangles[ti + 2] = vi + 2;

                    vi += 3;
                    ti += 3;
                }
            }
            else if (index == 15)
            {
                Vector3   p = new Vector3(grid.x, grid.y, 0);
                Vector3[] points = MetaballDefs.pointLookupTable[index];
                int[]     triangles = MetaballDefs.triangleLookupTable[index];
                int       j = 0, k = triangles.Length;
                for (j = 0; j < k; j += 3)
                {
                    Vector3 p0 = points[triangles[j]];
                    Vector3 p1 = points[triangles[j + 1]];
                    Vector3 p2 = points[triangles[j + 2]];

                    _vertices[vi]     = p + (p0 * _gridSize);
                    _vertices[vi + 1] = p + (p1 * _gridSize);
                    _vertices[vi + 2] = p + (p2 * _gridSize);

                    _triangles[ti]     = vi;
                    _triangles[ti + 1] = vi + 1;
                    _triangles[ti + 2] = vi + 2;

                    vi += 3;
                    ti += 3;
                }
            }
        }

        // clear unused portion of vertex and triangle buffers
        System.Array.Clear(_vertices, vi, _verticesLength - vi);
        System.Array.Clear(_triangles, ti, _trianglesLength - ti);

        // update mesh
        _mesh.Clear(false);
        _mesh.vertices  = _vertices;
        _mesh.triangles = _triangles;
    }