
Path and road generator
Posted Sunday, 7 October, 2012 - 04:11 by flopolocoThis is a research I made for generating paths and roads. I got tired of all those complicated and useless road generators, so I decided to make a very simple on my own. Probably it will be used in some future games I will make (mostly in Unity, that will be ported to).
I guess that it might be also very useful to use it in your games too, so grab it here study it and learn from it.
Room for improvments:
1. Smooth curve calculation: Bezier algorithm seem to suck a bit, I will try a different algorithm for even distribution.
2. Find a way to control the width of the path (on each cuve point) to add narrow or wider varieties.
3. Add UVs for textures
4. Add support for N handle points (now only limited to 4)
5. Add support for enclosed curve paths
using System; using System.Collections.Generic; using System.Drawing; using OpenTK; using OpenTK.Graphics.OpenGL; using OpenTK.Input; namespace ObjectOnBezier { public class Program : GameWindow { Matrix4 matrixProjection, matrixModelview; Random rand = new Random(); #region Path properties /// <summary>How many segments road has.</summary> int pathSegments = 20; /// <summary>The handles of the curve.</summary> Vector3[] handles = new Vector3[4]; /// <summary>Generated path that is based on handles.</summary> Vector3[] path; /// <summary>The actual vertex geometry of the path.</summary> Vector3[] geometry; #endregion /// <summary>This is the player movement along the path (added for test purposes only)</summary> float cycle = 0f; protected override void OnLoad(EventArgs e) { Width = 1024; Height = 768; GL.ClearColor(Color.DarkRed); GL.Enable(EnableCap.DepthTest); // Length of the path (for display purposes) float size = 25f; for (int i = 0; i < handles.Length; i++) handles[i] = new Vector3(0f, 0f, size - (i * size/2f)); path = new Vector3[pathSegments]; geometry = new Vector3[pathSegments * 2]; } protected override void OnResize(EventArgs e) { GL.Viewport(0, 0, Width, Height); matrixProjection = Matrix4.CreatePerspectiveFieldOfView( (float)Math.PI / 4, Width / (float)Height, 1f, 1000f); GL.MatrixMode(MatrixMode.Projection); GL.LoadMatrix(ref matrixProjection); } protected override void OnUpdateFrame(FrameEventArgs e) { // When player reaches and of the path then reset his position and change positions of handles cycle += (float)e.Time * 1f; if (cycle > 1f) { cycle = 0f; for (int i = 0; i < 4; i++) handles[i].X = (float)rand.Next(-10, 10); } } protected override void OnRenderFrame(FrameEventArgs e) { #region Camera GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); matrixModelview = Matrix4.LookAt(0f, 30f, -30f, 0f, 0f, 0f, 0f, 1f, 0f); GL.MatrixMode(MatrixMode.Modelview); GL.LoadMatrix(ref matrixModelview); #endregion #region Draw point handles (yellow large points) GL.PointSize(10f); GL.Color3(Color.Yellow); GL.Begin(BeginMode.Points); for (int i = 0; i < 4; i++) GL.Vertex3(handles[i]); GL.End(); #endregion #region Process path curve // Calculate positions points for (int i = 0; i < pathSegments; i++) { float t = i / (float) pathSegments; path[i] = CalculateBezierPoint( t, handles[0], handles[1], handles[2], handles[3]); } // Draw line of the curve path GL.PointSize(5f); GL.Color3(Color.Green); GL.Begin(BeginMode.LineStrip); for (int i = 0; i < pathSegments; i++) GL.Vertex3(path[i]); GL.End(); // Draw segment points (to see how the cuve path is divided) GL.PointSize(2f); GL.Color3(Color.White); GL.Begin(BeginMode.Points); for (int i = 0; i < pathSegments; i++) GL.Vertex3(path[i]); GL.End(); #endregion #region Process path geometry // Calculate geometry for (int i=0; i < pathSegments; i++) { Vector3 normal = new Vector3(0f); // Note: Because we need to look ahead 1 array index, we make // sure that we do not exceed limits of path[i] array. if (i < pathSegments - 1) { // Normal calculation: nx = by - ay, ny = -(bx - ax) normal = new Vector3( -(path[i+1].Z - path[i].Z), 0f, path[i+1].X - path[i].X ); normal.Normalize(); } // Store left extrusion (calculated normal + point position) geometry[i*2] = normal + path[i]; // Store right extrusion (flipped calculated normal + point position) geometry[(i*2)+1] = (normal * -1f) + path[i]; } // Draw geometry (only for test purposes) GL.PointSize(2f); GL.Color3(Color.Black); GL.Begin(BeginMode.Lines); // Don't ask: After of lots expirementation for (int i = 0; i < geometry.Length-4; i+=2) { // Left GL.Vertex3(geometry[i+0]); GL.Vertex3(geometry[i+2]); // Right GL.Vertex3(geometry[i+1]); GL.Vertex3(geometry[i+3]); // Bottom GL.Vertex3(geometry[i+2]); GL.Vertex3(geometry[i+3]); // Upper GL.Vertex3(geometry[i]); GL.Vertex3(geometry[i+1]); } GL.End(); // Draw points GL.PointSize(3f); GL.Color3(Color.Orange); GL.Begin(BeginMode.Points); for (int i = 0; i < geometry.Length; i++) GL.Vertex3(geometry[i]); GL.End(); #endregion #region Draw moving object GL.PointSize(15f); GL.Color3(Color.Pink); GL.Begin(BeginMode.Points); GL.Vertex3(CalculateBezierPoint(cycle, handles[0], handles[1], handles[2], handles[3])); GL.End(); #endregion SwapBuffers(); } Vector3 CalculateBezierPoint(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) { float u = 1 - t; float tt = t * t; float uu = u * u; float uuu = uu * u; float ttt = tt * t; Vector3 p = uuu * p0; p += 3 * uu * t * p1; p += 3 * u * tt * p2; p += ttt * p3; return p; } [STAThread] public static void Main() { using (Program p = new Program()) { p.Run(80f); } } } }
For any other comments or remarks or contributions write below.
- flopoloco's blog
- Login or register to post comments

