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; }
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; }