- Home /
Procedural mesh, using beziers for walls and roads
Hello. I have been trying to make a system for creating procedural walls (and roads) using beziers. Something something along the lines of the road system in Cities Skylines. My first idea was to use premade geometry and instantiate wallsegments at fixed intervals. But since i want to have the walls join at points on towers and buildings, the length of the walls has to be very precise. So I have been looking at procedural meshes and bezier splines and after scouring the web, I kindof made a somewhat usable piece of code. The tutorials I have found have been very specific and I am just not experianced enough with coding to be able to figure this out.
https://drive.google.com/folderview?id=0B4S0tkWTFjF3YjU0T2piZVM0eHM&usp=sharing Here is a link to the unity project.
Below I have posted the code i have stitched together from bits and pieces found on the web and altered to be somewhat consistent...
When the mouse is clicked you can drag the cursor to create a line of verticies. If shift is held down the wall can be curved. I can alter the height of the wall by adding more segments in the Y direction. The cursor snaps to the closest end point of existing walls.
But now I am lost. Adding triangles in a loop to the verticies is a nightmare. And how do i offset the verticies from the center of the line, and set their rotation to fit the curvature and direction of the wall?
I hope someone can help me. If you can point me to some other way to create procedural walls at runtime, that would be allso be fantastic. I have found several eksamples of this, but no tutoruals. I am so close! :) http://architred.blogspot.dk/2013/05/unity-wall-tool.html <-- this guy made it
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
public class NewWall : MonoBehaviour
{
bool creating;
public GameObject start;
public GameObject end;
public GameObject bezier;
public GameObject adfa;
public LayerMask wallLayer;
public GameObject wallPolePoint;
public int WallHeight = 3;
bool poleSnapping;
bool endPoleSnapping;
bool isCurving;
List<GameObject> poles;
// Use this for initialization
void Start()
{
poles = new List<GameObject>();
}
// Update is called once per frame
void Update()
{
startCursor();
getInput();
}
Vector3 getWorldPoint()
{
Ray ray = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<Camera>().ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, Mathf.Infinity, ~wallLayer))
{
return hit.point;
}
return Vector3.zero;
}
void getInput()
{
end.SetActive(false);
bezier.SetActive(false);
if (Input.GetMouseButtonDown(0))
{
setStart();
end.SetActive(true);
bezier.SetActive(true);
}
if (Input.GetKeyDown(KeyCode.LeftShift))
{
setBezier();
isCurving = true;
}
if (Input.GetKeyUp(KeyCode.LeftShift))
{
isCurving = false;
}
else if (Input.GetMouseButtonUp(0))
{
setEnd();
StartCoroutine(createWallSegments());
isCurving = false;
}
else
{
if (creating)
{
adjust();
end.SetActive(true);
bezier.SetActive(true);
}
}
}
Vector3 gridSnap(Vector3 originalPosition)
{
int granularity = 1;
Vector3 snappedPosition = new Vector3(Mathf.Floor((originalPosition.x / granularity) * granularity), originalPosition.y, Mathf.Floor(originalPosition.z / granularity) * granularity);
return snappedPosition;
}
void startCursor()
{
if (creating)
{
adjust();
}
else
{
if (GameObject.FindGameObjectsWithTag("Pole").Length == 0)
{
start.transform.position = gridSnap(getWorldPoint());
poleSnapping = false;
}
else if
(Vector3.Distance((getWorldPoint()), closestPoleTo(getWorldPoint()).transform.position) <= 5)
{
start.transform.position = closestPoleTo(getWorldPoint()).transform.position;
poleSnapping = true;
}
else
{
start.transform.position = gridSnap(getWorldPoint());
poleSnapping = false;
}
}
}
void setStart()
{
creating = true;
start.transform.position = gridSnap(getWorldPoint());
if (poleSnapping)
{
start.transform.position = closestPoleTo(getWorldPoint()).transform.position;
}
GameObject p1 = (GameObject)Instantiate(wallPolePoint, start.transform.position, start.transform.rotation);
p1.tag = "Pole";
poles.Add(p1);
}
void setEnd()
{
creating = false;
end.transform.position = gridSnap(getWorldPoint());
if (endPoleSnapping)
{
end.transform.position = closestPoleTo(getWorldPoint()).transform.position;
}
GameObject p2 = (GameObject)Instantiate(wallPolePoint, end.transform.position, end.transform.rotation);
p2.tag = "Pole";
poles.Add(p2);
}
void setBezier()
{
creating = true;
bezier.transform.position = gridSnap(getWorldPoint());
}
GameObject closestPoleTo(Vector3 worldPoint)
{
GameObject closest = null;
float distance = Mathf.Infinity;
float currentDistance = Mathf.Infinity;
foreach (GameObject p in poles)
{
currentDistance = Vector3.Distance(worldPoint, p.transform.position);
if (currentDistance < distance)
{
distance = currentDistance;
closest = p;
}
}
return closest;
}
void adjust()
{
if (GameObject.FindGameObjectsWithTag("Pole").Length == 0)
{
end.transform.position = gridSnap(getWorldPoint());
endPoleSnapping = false;
}
else if
(Vector3.Distance((getWorldPoint()), closestPoleTo(getWorldPoint()).transform.position) <= 5)
{
end.transform.position = closestPoleTo(getWorldPoint()).transform.position;
endPoleSnapping = true;
}
else
{
end.transform.position = gridSnap(getWorldPoint());
endPoleSnapping = false;
}
adjustWall();
}
void adjustWall()
{
Vector3 endTargetPostition = new Vector3(end.transform.position.x, start.transform.position.y, end.transform.position.z);
Vector3 startTargetPostition = new Vector3(start.transform.position.x, end.transform.position.y, start.transform.position.z);
start.transform.LookAt(endTargetPostition);
end.transform.LookAt(startTargetPostition);
Vector3 Distance = (start.transform.position + end.transform.position) / 2f;
if (isCurving == false)
{
bezier.transform.position = Distance;
}
}
//---------------------------------------------------------------------
//this is the mesh generation code
//---------------------------------------------------------------------
List<Vector3> vertices = new List<Vector3>();
private IEnumerator createWallSegments()
{
WaitForSeconds wait = new WaitForSeconds(0.05f);
Mesh mesh = new Mesh();
float distance = Mathf.Floor(Vector3.Distance(start.transform.position, end.transform.position) / 2);
int distanceInt = Convert.ToInt32(distance);
// set points of quadratic Bezier curve
Vector3 p0 = start.transform.position;
Vector3 p1 = bezier.transform.position;
Vector3 p2 = end.transform.position;
float t;
Vector3 position;
for (int i = 0, x = 0; x <= distance; x++)
{
for (int y = 0; y < WallHeight; y++, i++)
{
t = x / (distance);
position = (1.0f - t) * (1.0f - t) * p0 + 2.0f * (1.0f - t) * t * p1 + t * t * p2;
Vector3 newPos = new Vector3(position.x, position.y + y, position.z);
vertices.Add(newPos);
yield return wait;
}
}
mesh.vertices = vertices.ToArray();
Debug.Log(mesh.vertices.Length);
//List<int> triangles = new List<int>(mesh.triangles);
int[] triangles = new int[mesh.vertices.Length * 6];
for (int ti = 0, vi = 0, x = 0; x < WallHeight; x++, ti += 6, vi++)
{
triangles[ti] = vi;
triangles[ti + 3] = triangles[ti + 1] = vi + 1;
triangles[ti + 2] = triangles[ti + 5] = vi + WallHeight;
triangles[ti + 4] = vi + WallHeight + 1;
}
//I am able to make the first row, but I am at a loss on how to loop this code. Everything I have tryed have
//resultet in some strange behavior, with missing quads, half the wall facing the wrong way, or triangles joining
// verts on the far side of the wall..
mesh.triangles = triangles;
//mesh.triangles = triangles.ToArray();
MeshFilter filter = GetComponent<MeshFilter>();
if (filter != null)
{
filter.sharedMesh = mesh;
}
}
private void OnDrawGizmos()
{
if (vertices == null)
{
return;
}
Gizmos.color = Color.black;
for (int i = 0; i < vertices.Count; i++)
{
Gizmos.DrawSphere(vertices[i], 0.1f);
}
}
}
Your answer
Follow this Question
Related Questions
Filling the space between bezier curves with a texture, 1 Answer
detect if two objects in a list intersect in editor. 0 Answers
Extrude shape with sharp corners 0 Answers
Mesh generated from bezier curve loop going outside loop 0 Answers
iTween for Dynamically Moving Objects around a Sphere 0 Answers