Skip to content

Instantly share code, notes, and snippets.

@michaelbartnett
Created November 10, 2012 19:44
Show Gist options
  • Save michaelbartnett/4052250 to your computer and use it in GitHub Desktop.
Save michaelbartnett/4052250 to your computer and use it in GitHub Desktop.
Generate flat terrain meshes in Unity by hand
using UnityEngine;
using IEnumerator=System.Collections.IEnumerator;
[RequireComponent(typeof(MeshRenderer))]
[RequireComponent(typeof(MeshFilter))]
[ExecuteInEditMode]
public class DrawTerrain : MonoBehaviour
{
public int rows = 3;
public int columns = 3;
public Vector2 uvScale = Vector2.one;
public float vertVisitSpeed = 2;
private MeshFilter meshFilter;
private Mesh mesh;
public Vector3[] Vertices;
public Vector2[] UVs;
public int[] Indices;
public bool VisitingVertices { get; private set; }
void Awake()
{
meshFilter = GetComponent<MeshFilter>();
mesh = new Mesh();
meshFilter.mesh = mesh;
UpdateMeshSize();
}
public void UpdateMeshSize()
{
Vertices = GenVerts(rows, columns);
Indices = GenStripIndices(rows, columns);
UVs = GenTexCoords(rows, columns, uvScale);
mesh.Clear();
mesh.vertices = Vertices;
mesh.uv = UVs;
mesh.SetTriangleStrip(Indices, 0);
mesh.RecalculateNormals();
mesh.RecalculateBounds();
mesh.Optimize();
}
public void UpdateVertices()
{
mesh.vertices = Vertices;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
}
public void UpdateUVs()
{
mesh.uv = UVs;
mesh.RecalculateNormals();
}
public void StartVisitingVertices()
{
VisitingVertices = true;
StartCoroutine(VisitVerticesInTriOrder());
}
public void StopVisitingVertices()
{
VisitingVertices = false;
}
public void ToggleVisitingVertices()
{
if (VisitingVertices) {
StopVisitingVertices();
} else {
StartVisitingVertices();
}
}
private IEnumerator VisitVerticesInTriOrder()
{
var vertMarker = GameObject.CreatePrimitive(PrimitiveType.Sphere).transform;
vertMarker.localScale *= 0.4f;
while (true) {
int ctr = 0;
for (int i = 0; i < Indices.Length; i++) {
ctr++;
vertMarker.position = this.Vertices[Indices[i]];
//if (ctr % 3 == 1) {
vertMarker.renderer.enabled = false;
yield return new WaitForSeconds(1/vertVisitSpeed * 0.5f);
if (!VisitingVertices) break;
vertMarker.renderer.enabled = true;
//}
yield return new WaitForSeconds(1 / vertVisitSpeed);
if (!VisitingVertices) break;
}
yield return new WaitForSeconds(1 / vertVisitSpeed);
if (!VisitingVertices) break;
}
Object.Destroy(vertMarker.gameObject);
}
private static Vector3[] GenVerts(int rows, int cols)
{
var verts = new Vector3[rows * cols];
float xpos;
float ypos = (rows-1) * -0.5f;
//var sb = new System.Text.StringBuilder("VERTICES YO:\n");
for (int y = 0; y < rows; y++) {
xpos = -(cols-1) * 0.5f;
for (int x = 0; x < cols; x++) {
verts[y * cols + x] = new Vector3(xpos, 0, ypos);
xpos += 1.0f;
//sb.Append("$(y * cols + x):[$(x),$(y)]=($(xpos),$(ypos))\n")
}
ypos += 1.0f;
}
//Debug.Log(sb.ToString())
return verts;
}
private static int[] GenStripIndices(int rows, int cols)
{
int numIndices = 2*cols*rows - 2*cols + 2*rows - 2;
var indices = new int[numIndices];
// Make triangle strips with degenerate triangles
// with shared vertices at bottom-left and top-right of strip
int index = 0;
for (int y = 0; y < rows - 1; y++) {
indices[index++] = y * cols + (cols - 1);
for (int x = cols - 1; x >= 0; x--) {
indices[index++] = y * cols + x;
indices[index++] = (y + 1) * cols + x;
}
indices[index++] = (y + 1) * cols;
}
return indices;
}
private static Vector2[] GenTexCoords(int rows, int cols, Vector2 uvScale)
{
var texCoords = new Vector2[rows * cols];
float vInc = 1.0f / (rows - 1) * uvScale.y;
float uInc = 1.0f / (cols - 1) * uvScale.x;
DebugUtils.LogFormat("UV inc: {0},{1}", uInc, vInc);
int uvIndex = 0;
float vVal = 0f;
float uVal;
for (int v = 0; v < rows; v++) {
uVal = 0f;
for (int u = 0; u < cols; u++) {
texCoords[uvIndex] = new Vector2(uVal, vVal);
uVal += uInc;
uvIndex++;
}
vVal += vInc;
}
return texCoords;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment