Created
February 18, 2017 11:53
-
-
Save reveriejake/d1016a5e9b022b76c073bcc9332dc61d to your computer and use it in GitHub Desktop.
Pico Games - Marching Squares Algorithm Simple
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using PicoGames.Common; | |
namespace PicoGames.Terrains.MS2D | |
{ | |
public class MS2DTerrainChunk : MonoBehaviour | |
{ | |
private int width = 32; | |
private int height = 32; | |
public float cellScale = 1f; | |
public float uvScale = 0.25f; | |
public float squareInterpolation = 0; | |
public Material material; | |
//public MS2DTerrainData terrainGen; | |
private Voxel[,] voxelData; | |
[SerializeField, HideInInspector] | |
private MeshBuffer mBuffer; | |
private MeshBuffer Buffer | |
{ | |
get | |
{ | |
if (mBuffer == null) | |
mBuffer = CreateBuffer("Terrain"); | |
return mBuffer; | |
} | |
} | |
//private void Start() | |
//{ | |
// var offset = new Vector2(cellScale * width, cellScale * height) * -0.5f; | |
// voxelData = new Voxel[width + 1, height + 1]; | |
// for (int y = 0; y <= height; y++) | |
// { | |
// for (int x = 0; x <= width; x++) | |
// { | |
// var voxelPos = offset + new Vector2(x * cellScale, y * cellScale); | |
// var d = Vector2.Distance(voxelPos, Vector2.zero) / (Mathf.Min(width, height) * 0.5f) - Random.Range(0.9f, 1f); | |
// voxelData[x, y] = new Voxel(offset + new Vector2(x * cellScale, y * cellScale), d); | |
// } | |
// } | |
// UpdateMesh(); | |
//} | |
//private void OnValidate() | |
//{ | |
// Start(); | |
//} | |
public void SetCellCount(int width, int height) | |
{ | |
this.width = width; | |
this.height = height; | |
voxelData = new Voxel[width + 1, height + 1]; | |
var offset = new Vector2(cellScale * width, cellScale * height) * -0.5f; | |
for (int y = 0; y <= height; y++) | |
{ | |
for (int x = 0; x <= width; x++) | |
{ | |
var voxelPos = offset + new Vector2(x * cellScale, y * cellScale); | |
voxelData[x, y] = new Voxel(offset + new Vector2(x * cellScale, y * cellScale), -1f); | |
} | |
} | |
} | |
public void SetDensity(int x, int y, float density) | |
{ | |
if (x < 0 || x > width || y < 0 || y > height) | |
return; | |
voxelData[x, y].density = density; | |
} | |
public float GetDensity(int x, int y) | |
{ | |
if (x < 0 || x > width || y < 0 || y > height) | |
return -99; | |
return voxelData[x, y].density; | |
} | |
public void UpdateMesh() | |
{ | |
Buffer.Clear(); | |
for (int y = 0; y < height; y++) | |
{ | |
for (int x = 0; x < width; x++) | |
{ | |
AddCell(Buffer, voxelData[x, y], voxelData[x + 1, y], voxelData[x + 1, y + 1], voxelData[x, y + 1], uvScale); | |
} | |
} | |
//Outline.Clear(); | |
//if (showOutline) | |
//{ | |
// for (int y = 0; y < height; y++) | |
// { | |
// for (int x = 0; x < width; x++) | |
// { | |
// var voxel = voxelData[x, y]; | |
// for (int i = 0; i < voxel.edges.Count; i++) | |
// { | |
// var p0 = (Vector3)voxel.edges[i].p0 + new Vector3(0, 0, transform.position.z); | |
// var p1 = (Vector3)voxel.edges[i].p1 + new Vector3(0, 0, transform.position.z); | |
// var n = (Vector3)voxel.edges[i].normal * outlineSize; | |
// Outline.AddQuad(p0 + n, p1 + n, p1 - n, p0 - n); | |
// Outline.AddColor(outlineColor, outlineColor, outlineColor, outlineColor); | |
// } | |
// } | |
// } | |
//} | |
//Outline.Apply(); | |
Buffer.Apply(material); | |
} | |
private void AddCell(MeshBuffer buffer, Voxel a, Voxel b, Voxel c, Voxel d, float uvScale) | |
{ | |
if (a == null || b == null || c == null || d == null) | |
return; | |
var caseCode = GetCaseCode(a, b, c, d); | |
//a.edges.Clear(); | |
switch (caseCode) | |
{ | |
case 0: | |
return; | |
case 1: | |
{ | |
var p0 = Interpolate(a, b); | |
var p1 = Interpolate(d, a); | |
//a.edges.Add(new VoxelEdge(p0, p1)); | |
buffer.AddTriangle(a.position, p0, p1); | |
buffer.AddUVs(a.position * uvScale, p0 * uvScale, p1 * uvScale); | |
} | |
return; | |
case 2: | |
{ | |
var p0 = Interpolate(a, b); | |
var p1 = Interpolate(b, c); | |
//a.edges.Add(new VoxelEdge(p1, p0)); | |
buffer.AddTriangle(p0, b.position, p1); | |
buffer.AddUVs(p0 * uvScale, b.position * uvScale, p1 * uvScale); | |
} | |
return; | |
case 3: | |
{ | |
var p0 = Interpolate(b, c); | |
var p1 = Interpolate(d, a); | |
//a.edges.Add(new VoxelEdge(p0, p1)); | |
buffer.AddQuad(a.position, b.position, p0, p1); | |
buffer.AddUVs(a.position * uvScale, b.position * uvScale, p0 * uvScale, p1 * uvScale); | |
} | |
return; | |
case 4: | |
{ | |
var p0 = Interpolate(b, c); | |
var p1 = Interpolate(c, d); | |
//a.edges.Add(new VoxelEdge(p1, p0)); | |
buffer.AddTriangle(p0, c.position, p1); | |
buffer.AddUVs(p0 * uvScale, c.position * uvScale, p1 * uvScale); | |
} | |
return; | |
case 5: | |
{ | |
var avg = (a.density + b.density + c.density + d.density) * 0.25f; | |
var p0 = Interpolate(a, b); | |
var p1 = Interpolate(b, c); | |
var p2 = Interpolate(c, d); | |
var p3 = Interpolate(d, a); | |
if (avg < 0) | |
{ | |
//a.edges.Add(new VoxelEdge(p0, p1)); | |
//a.edges.Add(new VoxelEdge(p2, p3)); | |
buffer.AddHexagon(a.position, p0, p1, c.position, p2, p3); | |
buffer.AddUVs(a.position * uvScale, p0 * uvScale, p1 * uvScale, c.position * uvScale, p2 * uvScale, p3 * uvScale); | |
} | |
else | |
{ | |
//a.edges.Add(new VoxelEdge(p0, p3)); | |
//a.edges.Add(new VoxelEdge(p1, p2)); | |
buffer.AddTriangle(a.position, p0, p3); | |
buffer.AddUVs(a.position * uvScale, p0 * uvScale, p3 * uvScale); | |
buffer.AddTriangle(p1, c.position, p2); | |
buffer.AddUVs(p1 * uvScale, c.position * uvScale, p2 * uvScale); | |
} | |
} | |
return; | |
case 6: | |
{ | |
var p0 = Interpolate(a, b); | |
var p1 = Interpolate(c, d); | |
//a.edges.Add(new VoxelEdge(p1, p0)); | |
buffer.AddQuad(p0, b.position, c.position, p1); | |
buffer.AddUVs(p0 * uvScale, b.position * uvScale, c.position * uvScale, p1 * uvScale); | |
} | |
return; | |
case 7: | |
{ | |
var p0 = Interpolate(c, d); | |
var p1 = Interpolate(d, a); | |
//a.edges.Add(new VoxelEdge(p0, p1)); | |
buffer.AddPentagon(a.position, b.position, c.position, p0, p1); | |
buffer.AddUVs(a.position * uvScale, b.position * uvScale, c.position * uvScale, p0 * uvScale, p1 * uvScale); | |
} | |
return; | |
case 8: | |
{ | |
var p0 = Interpolate(c, d); | |
var p1 = Interpolate(d, a); | |
//a.edges.Add(new VoxelEdge(p1, p0)); | |
buffer.AddTriangle(p0, d.position, p1); | |
buffer.AddUVs(p0 * uvScale, d.position * uvScale, p1 * uvScale); | |
} | |
return; | |
case 9: | |
{ | |
var p0 = Interpolate(a, b); | |
var p1 = Interpolate(c, d); | |
//a.edges.Add(new VoxelEdge(p0, p1)); | |
buffer.AddQuad(a.position, p0, p1, d.position); | |
buffer.AddUVs(a.position * uvScale, p0 * uvScale, p1 * uvScale, d.position * uvScale); | |
} | |
return; | |
case 10: | |
{ | |
var avg = (a.density + b.density + c.density + d.density) * 0.25f; | |
var p0 = Interpolate(a, b); | |
var p1 = Interpolate(b, c); | |
var p2 = Interpolate(c, d); | |
var p3 = Interpolate(d, a); | |
if (avg < 0) | |
{ | |
//a.edges.Add(new VoxelEdge(p0, p3)); | |
//a.edges.Add(new VoxelEdge(p1, p2)); | |
buffer.AddHexagon(p0, b.position, p1, p2, d.position, p3); | |
buffer.AddUVs(p0 * uvScale, b.position * uvScale, p1 * uvScale, p2 * uvScale, d.position * uvScale, p3 * uvScale); | |
} | |
else | |
{ | |
//a.edges.Add(new VoxelEdge(p0, p1)); | |
//a.edges.Add(new VoxelEdge(p2, p3)); | |
buffer.AddTriangle(p0, b.position, p1); | |
buffer.AddUVs(p0 * uvScale, b.position * uvScale, p1 * uvScale); | |
buffer.AddTriangle(p2, d.position, p3); | |
buffer.AddUVs(p2 * uvScale, d.position * uvScale, p3 * uvScale); | |
} | |
} | |
return; | |
case 11: | |
{ | |
var p0 = Interpolate(b, c); | |
var p1 = Interpolate(c, d); | |
//a.edges.Add(new VoxelEdge(p0, p1)); | |
buffer.AddPentagon(a.position, b.position, p0, p1, d.position); | |
buffer.AddUVs(a.position * uvScale, b.position * uvScale, p0 * uvScale, p1 * uvScale, d.position * uvScale); | |
} | |
return; | |
case 12: | |
{ | |
var p0 = Interpolate(b, c); | |
var p1 = Interpolate(d, a); | |
//a.edges.Add(new VoxelEdge(p1, p0)); | |
buffer.AddQuad(p0, c.position, d.position, p1); | |
buffer.AddUVs(p0 * uvScale, c.position * uvScale, d.position * uvScale, p1 * uvScale); | |
} | |
return; | |
case 13: | |
{ | |
var p0 = Interpolate(a, b); | |
var p1 = Interpolate(b, c); | |
//a.edges.Add(new VoxelEdge(p0, p1)); | |
buffer.AddPentagon(a.position, p0, p1, c.position, d.position); | |
buffer.AddUVs(a.position * uvScale, p0 * uvScale, p1 * uvScale, c.position * uvScale, d.position * uvScale); | |
} | |
return; | |
case 14: | |
{ | |
var p0 = Interpolate(a, b); | |
var p1 = Interpolate(d, a); | |
//a.edges.Add(new VoxelEdge(p1, p0)); | |
buffer.AddPentagon(p0, b.position, c.position, d.position, p1); | |
buffer.AddUVs(p0 * uvScale, b.position * uvScale, c.position * uvScale, d.position * uvScale, p1 * uvScale); | |
} | |
return; | |
case 15: | |
{ | |
buffer.AddQuad(a.position, b.position, c.position, d.position); | |
buffer.AddUVs(a.position * uvScale, b.position * uvScale, c.position * uvScale, d.position * uvScale); | |
} | |
return; | |
} | |
} | |
private int GetCaseCode(Voxel a, Voxel b, Voxel c, Voxel d, float surface = 0) | |
{ | |
var caseCode = ((a.density < surface ? 1 : 0) | (b.density < surface ? 2 : 0) | (c.density < surface ? 4 : 0) | (d.density < surface ? 8 : 0)); | |
return caseCode; | |
} | |
private Vector3 Interpolate(Voxel a, Voxel b, float surface = 0) | |
{ | |
var t = Mathf.Lerp(((surface - a.density) / (b.density - a.density)), 0.5f, squareInterpolation); | |
return Vector3.Lerp(a.position, b.position, t); | |
} | |
public MeshBuffer CreateBuffer(string id) | |
{ | |
var bferGO = transform.Find(id + "_MBFER"); | |
if(bferGO != null) | |
return bferGO.GetComponent<MeshBuffer>(); | |
var mbfr = new GameObject(id + "_MBFER").AddComponent<MeshBuffer>(); | |
mbfr.gameObject.hideFlags = HideFlags.HideAndDontSave; | |
mbfr.transform.parent = transform; | |
mbfr.transform.localPosition = Vector3.zero; | |
mbfr.transform.localRotation = Quaternion.identity; | |
mbfr.transform.localScale = Vector2.one; | |
return mbfr; | |
} | |
} | |
[System.Serializable] | |
public class Voxel | |
{ | |
public float density; | |
public Vector2 position; | |
//public List<VoxelEdge> edges; | |
public Voxel(Vector2 position, float density) | |
{ | |
this.density = density; | |
this.position = position; | |
//this.edges = new List<VoxelEdge>(); | |
} | |
} | |
//[System.Serializable] | |
//public class VoxelEdge | |
//{ | |
// public Vector2 p0; | |
// public Vector2 p1; | |
// public Vector2 normal; | |
// public VoxelEdge(Vector2 p0, Vector2 p1) | |
// { | |
// this.p0 = p0; | |
// this.p1 = p1; | |
// var d = (p1 - p0); | |
// normal = new Vector2(d.y, -d.x).normalized; | |
// } | |
//} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment