Skip to content

Instantly share code, notes, and snippets.

@reveriejake
Created February 18, 2017 11:53
Show Gist options
  • Save reveriejake/d1016a5e9b022b76c073bcc9332dc61d to your computer and use it in GitHub Desktop.
Save reveriejake/d1016a5e9b022b76c073bcc9332dc61d to your computer and use it in GitHub Desktop.
Pico Games - Marching Squares Algorithm Simple
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