public BezierCurve3(BezierCurve3 source) { SetControlPoints((Vector3[])source.ControlPoints.Clone()); }
/// <summary> /// Generates river meshes /// </summary> /// <param name="waterLevel"></param> /// <returns>Combination corner index-mesh</returns> public Dictionary<int, Mesh> GetMeshesForRivers(float waterLevel) { Dictionary<int, Mesh> ma = new Dictionary<int, Mesh>();//Key is index of the corner, Value is Mesh for that corner. Mesh m; Edge e1, e2; int e1ind, e2ind; BezierCurve3 bc1 = new BezierCurve3(), bc2 = new BezierCurve3(); Corner c; Vector3 v1, v2; Vector3 midpoint1, midpoint2, midpoint3, midpoint4, midpoint5, midpoint6; Vector3 p1, p2, p3; int j; float sqrmin = waterLevel * waterLevel; int edgesWithWater; float f, f2; #region vertices and indices declaration const int RiverToOceanVerticesPerSide = 5; const int RiverDoubleVerticesPerSide = 9; const int RiverTripleVerticesPerSide = 9; int[] indicesRiverStart = new int[] { 0, 1, 2 }; int[] indicesRiverToOcean = new int[] { 0, 1, 5, 5, 1, 6, 1, 2, 6, 6, 2, 7, 2, 3, 7, 7, 3, 8, 3, 4, 8, 8, 4, 9 }; int[] indicesRiverDouble = new int[] { 0, 1, 9, 9, 1, 10, 1, 2, 10, 10, 2, 11, 2, 3, 11, 11, 3, 12, 3, 4, 12, 12, 4, 13, 4, 5, 13, 13, 5, 14, 5, 6, 14, 14, 6, 15, 6, 7, 15, 15, 7, 16, 7, 8, 16, 16, 8, 17 }; int[] indicesRiverTriple = new int[] { 0, 1, 26, 26, 1, 25, 1, 2, 25, 25, 2, 24, 2, 3, 24, 24, 3, 23, 3, 4, 23, 23, 4, 22, 9, 10, 8, 8, 10, 7, 10, 11, 7, 7, 11, 6, 11, 12, 6, 6, 12, 5, 12, 13, 5, 5, 13, 4, 18, 19, 17, 17, 19, 16, 19, 20, 16, 16, 20, 15, 20, 21, 15, 15, 21, 14, 21, 22, 14, 14, 22, 13, 4, 13, 22 }; Vector3[] verticesRiverStart = new Vector3[3]; Vector3[] verticesRiverToOcean = new Vector3[RiverToOceanVerticesPerSide * 2]; Vector3[] verticesRiverDouble = new Vector3[RiverDoubleVerticesPerSide * 2]; Vector3[] verticesRiverTriple = new Vector3[RiverTripleVerticesPerSide * 3]; #endregion for (int i = 0; i < corners.Count; i++)//Loop through all corners { c = corners[i]; edgesWithWater = (c.edges[0].type == Edge.EdgeType.River ? 1 : 0) + (c.edges[1].type == Edge.EdgeType.River ? 1 : 0) + (c.edges[2].type == Edge.EdgeType.River ? 1 : 0);//Count river edges if (edgesWithWater == 0)//No rivers near corner continue; #region 1 edge with river if (edgesWithWater == 1)//1 edge with river { e1ind = (c.edges[0].type == Edge.EdgeType.River ? 0 : (c.edges[1].type == Edge.EdgeType.River ? 1 : 2));//Get the river edge e1 = c.edges[e1ind]; #region outflow to ocean if (IsCornerNearNodeOfType(c, Node.NodeType.Sea))//Outflow to ocean { v2 = (e1.C1.Position + e1.C2.Position) / 2;//Get edge middle f = e1.riverWidth / 20;//River width v1 = Vector3.Cross(e1.GetOtherCorner(c).Position - c.Position, c.Position).normalized * f;//Midpoint offset midpoint1 = v2 + v1;//Compute midpoints midpoint2 = v2 - v1; p1 = (c.edges[(e1ind + 1) % 3].GetOtherCorner(c).Position - c.Position).normalized * (f * 3) + c.Position;//Compute middle of other two edges p2 = (c.edges[(e1ind + 2) % 3].GetOtherCorner(c).Position - c.Position).normalized * (f * 3) + c.Position; //Determine closest points if (((midpoint1 - p1).sqrMagnitude + (midpoint2 - p2).sqrMagnitude) < ((midpoint1 - p2).sqrMagnitude + (midpoint2 - p1).sqrMagnitude))//m1 to v1 { bc1.StartPoint = midpoint1; bc1.EndPoint = p1; bc1.P1 = c.Position + v1; bc2.StartPoint = midpoint2; bc2.EndPoint = p2; bc2.P1 = c.Position - v1; } else//m1 to v2 { bc1.StartPoint = midpoint1; bc1.EndPoint = p2; bc1.P1 = c.Position + v1; bc2.StartPoint = midpoint2; bc2.EndPoint = p1; bc2.P1 = c.Position - v1; } for (j = 0, f = 0; j < RiverToOceanVerticesPerSide; j++, f += (1f / (RiverToOceanVerticesPerSide - 1)))//Get points from Bezier curve { verticesRiverToOcean[j] = bc1.GetPoint(f); verticesRiverToOcean[j + RiverToOceanVerticesPerSide] = bc2.GetPoint(f); } for (j = 0; j < verticesRiverToOcean.Length; j++)//Don't let rivers drop below ocean level if (verticesRiverToOcean[j].sqrMagnitude < sqrmin) verticesRiverToOcean[j] = verticesRiverToOcean[j].normalized * waterLevel; //Create mesh OrderMeshTriangles(verticesRiverToOcean, indicesRiverToOcean); m = new Mesh(); m.vertices = verticesRiverToOcean; m.SetIndices(indicesRiverToOcean, MeshTopology.Triangles, 0); ma.Add(i, m); }//Outflow to ocean #endregion #region river start else//River start { verticesRiverStart[0] = c.Position; v2 = (e1.C1.Position + e1.C2.Position) / 2;//Get edge middle v1 = Vector3.Cross(e1.C1.Position - e1.C2.Position, c.Position).normalized * (e1.riverWidth / 20f);//Midpoint offset verticesRiverStart[1] = v2 + v1;//Midpoints verticesRiverStart[2] = v2 - v1; //Create mesh OrderMeshTriangles(verticesRiverStart, indicesRiverStart); m = new Mesh(); m.vertices = verticesRiverStart; m.SetIndices(indicesRiverStart, MeshTopology.Triangles, 0); ma.Add(i, m); } #endregion }//1 edge with river #endregion #region 2 edges with river else if (edgesWithWater == 2)//2 edges with water { e1ind = (c.edges[0].type == Edge.EdgeType.River ? 0 : 1);//Find river edges e1 = c.edges[e1ind]; e2ind = (c.edges[2].type == Edge.EdgeType.River ? 2 : 1); e2 = c.edges[e2ind]; f = e1.riverWidth / 20;//River width v2 = p1 = (e1.C1.Position + e1.C2.Position) / 2;//Edge middle v1 = Vector3.Cross(e1.GetOtherCorner(c).Position - c.Position, c.Position).normalized * f;//Midpoint offset midpoint1 = v2 + v1;//Midpoints midpoint2 = v2 - v1; f = e2.riverWidth / 20;//River width v2 = (e2.C1.Position + e2.C2.Position) / 2;//Edge middle v1 = Vector3.Cross(e2.GetOtherCorner(c).Position - c.Position, c.Position).normalized * f;//Midpoint offset midpoint3 = v2 + v1;//Midpoints midpoint4 = v2 - v1; p1 = c.Position - (p1 + v2) / 2;//Offset for Bezier intermediate point //1st curve bc1.StartPoint = midpoint1; bc1.EndPoint = midpoint4; bc1.P1 = (midpoint1 + midpoint4) / 2 + p1; //2nd curve bc2.StartPoint = midpoint2; bc2.EndPoint = midpoint3; bc2.P1 = (midpoint2 + midpoint3) / 2 + p1; for (j = 0, f = 0; j < RiverDoubleVerticesPerSide; j++, f += (1f / (RiverDoubleVerticesPerSide - 1)))//Get points from Bezier curve { verticesRiverDouble[j] = bc1.GetPoint(f); verticesRiverDouble[j + RiverDoubleVerticesPerSide] = bc2.GetPoint(f); } //Create mesh OrderMeshTriangles(verticesRiverDouble, indicesRiverDouble); m = new Mesh(); m.vertices = verticesRiverDouble; m.SetIndices(indicesRiverDouble, MeshTopology.Triangles, 0); ma.Add(i, m); }//2 edges with water #endregion #region 3 edges with river else { e1 = c.edges[0]; f = e1.riverWidth / 20;//River width v2 = p1 = (e1.C1.Position + e1.C2.Position) / 2;//Edge middle v1 = Vector3.Cross(e1.GetOtherCorner(c).Position - c.Position, c.Position).normalized * f;//Midpoint offset midpoint1 = v2 + v1;//Midpoints midpoint2 = v2 - v1; e1 = c.edges[1]; f = e1.riverWidth / 20;//River width v2 = p2 = (e1.C1.Position + e1.C2.Position) / 2;//Edge middle v1 = Vector3.Cross(e1.GetOtherCorner(c).Position - c.Position, c.Position).normalized * f;//Midpoint offset midpoint3 = v2 + v1;//Midpoints midpoint4 = v2 - v1; e1 = c.edges[2]; f = e1.riverWidth / 20;//River width v2 = p3 = (e1.C1.Position + e1.C2.Position) / 2;//Edge middle v1 = Vector3.Cross(e1.GetOtherCorner(c).Position - c.Position, c.Position).normalized * f;//Midpoint offset midpoint5 = v2 + v1;//Midpoints midpoint6 = v2 - v1; #region edge1-edge2 //Find closest midpoints v1 = midpoint1; v2 = midpoint3; f = (v1 - v2).sqrMagnitude; if ((f2 = (midpoint2 - midpoint3).sqrMagnitude) < f) { f = f2; v1 = midpoint2; } if ((f2 = (midpoint1 - midpoint4).sqrMagnitude) < f) { f = f2; v1 = midpoint1; v2 = midpoint4; } if ((f2 = (midpoint2 - midpoint4).sqrMagnitude) < f) { v1 = midpoint2; v2 = midpoint4; } //Bezier curve bc1.StartPoint = v1; bc1.EndPoint = v2; bc1.P1 = (v1 + v2) / 2 + (c.Position - (p1 + p2) / 2); for (j = 0, f = 0; j < RiverTripleVerticesPerSide; j++, f += (1f / (RiverTripleVerticesPerSide - 1)))//Get points from Bezier curve verticesRiverTriple[j] = bc1.GetPoint(f); #endregion #region edge2-edge3 //find closest midpoints v1 = midpoint3; v2 = midpoint5; f = (v1 - v2).sqrMagnitude; if ((f2 = (midpoint4 - midpoint5).sqrMagnitude) < f) { f = f2; v1 = midpoint4; } if ((f2 = (midpoint3 - midpoint6).sqrMagnitude) < f) { f = f2; v1 = midpoint3; v2 = midpoint6; } if ((f2 = (midpoint4 - midpoint6).sqrMagnitude) < f) { v1 = midpoint4; v2 = midpoint6; } //Bezier curve bc1.StartPoint = v1; bc1.EndPoint = v2; bc1.P1 = (v1 + v2) / 2 + (c.Position - (p2 + p3) / 2); for (j = 0, f = 0; j < RiverTripleVerticesPerSide; j++, f += (1f / (RiverTripleVerticesPerSide - 1)))//Get points from Bezier curve verticesRiverTriple[j + RiverTripleVerticesPerSide] = bc1.GetPoint(f); #endregion #region edge1-edge3 //find closest midpoints v1 = midpoint1; v2 = midpoint5; f = (v1 - v2).sqrMagnitude; if ((f2 = (midpoint2 - midpoint5).sqrMagnitude) < f) { f = f2; v1 = midpoint2; } if ((f2 = (midpoint1 - midpoint6).sqrMagnitude) < f) { f = f2; v1 = midpoint1; v2 = midpoint6; } if ((f2 = (midpoint2 - midpoint6).sqrMagnitude) < f) { v1 = midpoint2; v2 = midpoint6; } //Bezier curve bc1.StartPoint = v2; bc1.EndPoint = v1; bc1.P1 = (v1 + v2) / 2 + (c.Position - (p1 + p3) / 2); for (j = 0, f = 0; j < RiverTripleVerticesPerSide; j++, f += (1f / (RiverTripleVerticesPerSide - 1)))//Get points from Bezier curve verticesRiverTriple[j + RiverTripleVerticesPerSide + RiverTripleVerticesPerSide] = bc1.GetPoint(f); #endregion //Create mesh OrderMeshTriangles(verticesRiverTriple, indicesRiverTriple); m = new Mesh(); m.vertices = verticesRiverTriple; m.SetIndices(indicesRiverTriple, MeshTopology.Triangles, 0); ma.Add(i, m); } #endregion }//Loop through all corners return ma; }
public RailSegment(BezierCurve3 curve, RailPiece railPiece) { RailPiece = railPiece; Curve = curve; }
public void CreateGeometry(RailSegment[] railSegments) { var curveTangents = new List <Vector3> [railSegments.Length]; var curvePositions = new List <Vector3> [railSegments.Length]; int crossSectionVertexCount = m_geometryDescription.CrossSectionPositions.Length; int vertexCount = 0; int triangleCount = 0; for (int k = 0; k < railSegments.Length; k++) { BezierCurve3 curve = railSegments[k].Curve; curveTangents[k] = new List <Vector3>(); // curvePositions[k] = curve.GetAngleApproximationWithTangents(0.0025f, curveTangents[k]); curvePositions[k] = curve.GetDistanceApproximationWithTangents(0.05f, curveTangents[k]); vertexCount += crossSectionVertexCount * curvePositions[k].Count; triangleCount += 2 * (curvePositions[k].Count - 1) * (crossSectionVertexCount - 1); } var positions = new Vector3[vertexCount]; var normals = new Vector3[vertexCount]; var uvs = new Vector2[vertexCount]; var indices = new int[3 * triangleCount]; int vertexIndex = 0; int indexIndex = 0; for (int k = 0; k < railSegments.Length; k++) { int processedVertexCount = vertexIndex; float currentU = 0; for (int crossSectionIndex = 0; crossSectionIndex < curvePositions[k].Count; crossSectionIndex++) { Vector3 point = curvePositions[k][crossSectionIndex]; Vector3 tangent = curveTangents[k][crossSectionIndex]; Matrix4x4 transform = MatrixHelpers.CreateLookAt(point, tangent, Vector3.up); for (int crossSectionVertexIndex = 0; crossSectionVertexIndex < crossSectionVertexCount; crossSectionVertexIndex++) { Vector2 position2D = m_geometryDescription.CrossSectionPositions[crossSectionVertexIndex]; var positionLocal = new Vector3(0, position2D.y, -position2D.x); Vector2 d; if (crossSectionVertexIndex < crossSectionVertexCount - 1) { Vector2 nextPosition2D = m_geometryDescription.CrossSectionPositions[crossSectionVertexIndex + 1]; if (nextPosition2D == position2D) { // Normal is 'plane' normal, i.e. only depends on line segment Vector2 previousPosition2D = m_geometryDescription.CrossSectionPositions[crossSectionVertexIndex - 1]; d = position2D - previousPosition2D; } else { d = nextPosition2D - position2D; if (crossSectionVertexIndex > 0) { // Normal is 'vertex' normal, i.e. the average of the line segment and previous line segment Vector2 previousPosition2D = m_geometryDescription.CrossSectionPositions[crossSectionVertexIndex - 1]; d += position2D - previousPosition2D; } } } else { d = position2D - m_geometryDescription.CrossSectionPositions[crossSectionVertexIndex - 1]; } var normalLocal = new Vector3(0, d.x, d.y); normalLocal.Normalize(); Vector3 positionGlobal = transform.MultiplyPoint(positionLocal); Vector3 normalGlobal = transform.MultiplyVector(normalLocal); positions[vertexIndex] = positionGlobal; normals[vertexIndex] = normalGlobal; uvs[vertexIndex] = new Vector2(currentU, m_geometryDescription.CrossSectionVs[crossSectionVertexIndex]); vertexIndex++; } if (crossSectionIndex < curvePositions[k].Count - 1) { Vector3 step = curvePositions[k][crossSectionIndex + 1] - curvePositions[k][crossSectionIndex]; currentU += m_geometryDescription.DeltaUPerMetre * step.magnitude; } } for (int crossSectionIndex = 0; crossSectionIndex < curvePositions[k].Count - 1; crossSectionIndex++) { int startIndex = processedVertexCount + crossSectionIndex * m_geometryDescription.CrossSectionPositions.Length; for (int crossSectionVertexIndex = 0; crossSectionVertexIndex < crossSectionVertexCount - 1; crossSectionVertexIndex++) { indices[indexIndex + 0] = startIndex + crossSectionVertexIndex; indices[indexIndex + 1] = startIndex + crossSectionVertexIndex + 1; indices[indexIndex + 2] = startIndex + crossSectionVertexCount + crossSectionVertexIndex; indices[indexIndex + 3] = startIndex + crossSectionVertexIndex + 1; indices[indexIndex + 4] = startIndex + crossSectionVertexCount + crossSectionVertexIndex + 1; indices[indexIndex + 5] = startIndex + crossSectionVertexCount + crossSectionVertexIndex; indexIndex += 6; } } } Mesh mesh = GameObject.GetComponent <MeshFilter>().mesh; mesh.Clear(); mesh.vertices = positions; mesh.normals = normals; mesh.uv = uvs; mesh.triangles = indices; }
public RailSegment(BezierCurve3 curve) { Curve = curve; }