/// <summary> /// Test column vertices /// </summary> //[Test] public static void TestColumnVertices() { TrackColumns colunms = null; TestGame.Start( delegate { colunms = new TrackColumns(new List<TrackVertex>(), null); }, delegate { // Draw the line for each line part for (int num = 0; num < colunms.BaseColumnVertices.Length - 1; num++) BaseGame.DrawLine( colunms.BaseColumnVertices[num].pos, colunms.BaseColumnVertices[num + 1].pos, Color.White); // Show normal and tangent vectors for each point for (int num = 0; num < colunms.BaseColumnVertices.Length; num++) { BaseGame.DrawLine( colunms.BaseColumnVertices[num].pos, colunms.BaseColumnVertices[num].pos + colunms.BaseColumnVertices[num].normal * 10, Color.Red); BaseGame.DrawLine( colunms.BaseColumnVertices[num].pos, colunms.BaseColumnVertices[num].pos + colunms.BaseColumnVertices[num].tangent * 10, Color.Blue); } // for (num) }); }
/// <summary> /// Generate vertices and objects /// </summary> private void GenerateVerticesAndObjects(Landscape landscape) { #region Generate the road vertices // Each road segment gets 5 points: // left, left middle, middle, right middle, right. // The reason for this is that we would bad triangle errors if the // road gets wider and wider. This happens because we need to render // quad, but we can only render triangles, which often have different // orientations, which makes the road very bumpy. This still happens // with 8 polygons instead of 2, but it is much better this way. // Another trick is not to do so much iterations in TrackLine, which // causes this problem. Better to have a not so round track, but at // least the road up/down itself is smooth. // The last point is duplicated (see TrackLine) because we have 2 sets // of texture coordinates for it (begin block, end block). // So for the index buffer we only use points.Count-1 blocks. roadVertices = new TangentVertex[points.Count * 5]; // Current texture coordinate for the roadway (in direction of movement) for (int num = 0; num < points.Count; num++) { // Get vertices with help of the properties in the TrackVertex class. // For the road itself we only need vertices for the left and right // side, which are vertex number 0 and 1. roadVertices[num * 5 + 0] = points[num].RightTangentVertex; roadVertices[num * 5 + 1] = points[num].MiddleRightTangentVertex; roadVertices[num * 5 + 2] = points[num].MiddleTangentVertex; roadVertices[num * 5 + 3] = points[num].MiddleLeftTangentVertex; roadVertices[num * 5 + 4] = points[num].LeftTangentVertex; } // for (num) roadVb = new VertexBuffer( BaseGame.Device, typeof(TangentVertex), roadVertices.Length, BufferUsage.WriteOnly); roadVb.SetData(roadVertices); // Also calculate all indices, we have 8 polygons for each segment with // 3 vertices each. We got 1 segment less than points because the // last point is duplicated (different tex coords). int[] indices = new int[(points.Count - 1) * 8 * 3]; int vertexIndex = 0; for (int num = 0; num < points.Count - 1; num++) { // We only use 3 vertices (and the next 3 vertices), // but we have to construct all 24 indices for our 4 polygons. for (int sideNum = 0; sideNum < 4; sideNum++) { // Each side needs 2 polygons. // 1. Polygon indices[num * 24 + 6 * sideNum + 0] = vertexIndex + sideNum; indices[num * 24 + 6 * sideNum + 1] = vertexIndex + 5 + 1 + sideNum; indices[num * 24 + 6 * sideNum + 2] = vertexIndex + 5 + sideNum; // 2. Polygon indices[num * 24 + 6 * sideNum + 3] = vertexIndex + 5 + 1 + sideNum; indices[num * 24 + 6 * sideNum + 4] = vertexIndex + sideNum; indices[num * 24 + 6 * sideNum + 5] = vertexIndex + 1 + sideNum; } // for (num) // Go to the next 5 vertices vertexIndex += 5; } // for (num) // Set road back index buffer roadIb = new IndexBuffer( BaseGame.Device, typeof(int), indices.Length, BufferUsage.WriteOnly); roadIb.SetData(indices); #endregion #region Generate the road back vertices // We need 4 vertices per cross-section edge of the road back hull roadBackVertices = new TangentVertex[points.Count * 4]; for (int num = 0; num < points.Count; num++) { // Left side of the road roadBackVertices[num * 4 + 0] = points[num].LeftTangentVertex; roadBackVertices[num * 4 + 0].uv = new Vector2( roadBackVertices[num * 4 + 0].U * RoadBackHullTextureWidthFactor, 0.0f); // Left lower side of the road roadBackVertices[num * 4 + 1] = points[num].BottomLeftSideTangentVertex; roadBackVertices[num * 4 + 1].uv = new Vector2( roadBackVertices[num * 4 + 0].U * RoadBackHullTextureWidthFactor, RoadBackSideTextureHeight); // Right lower side of the road roadBackVertices[num * 4 + 2] = points[num].BottomRightSideTangentVertex; roadBackVertices[num * 4 + 2].uv = new Vector2( roadBackVertices[num * 4 + 0].U * RoadBackHullTextureWidthFactor, 1.0f - RoadBackSideTextureHeight); // Right side of the road roadBackVertices[num * 4 + 3] = points[num].RightTangentVertex; roadBackVertices[num * 4 + 3].uv = new Vector2( roadBackVertices[num * 4 + 3].U * RoadBackHullTextureWidthFactor, 1.0f); } // for (num) // Set road back vertex buffer roadBackVb = new VertexBuffer( BaseGame.Device, typeof(TangentVertex), roadBackVertices.Length, BufferUsage.WriteOnly); roadBackVb.SetData(roadBackVertices); // Also calculate all indices, we have 6 polygons for each segment with // 3 vertices each. We got 1 segment less than points because the // last point is duplicated (different tex coords). int[] backIndices = new int[(points.Count-1) * 6 * 3]; vertexIndex = 0; for (int num = 0; num < points.Count-1; num++) { // We only use 4 vertices (and the next 4 vertices), // but we have to construct all 18 indices for our 6 polygons. for (int sideNum = 0; sideNum < 3; sideNum++) { // Each side needs 2 polygons. // 1. Polygon backIndices[num * 18 + 6 * sideNum + 0] = vertexIndex + sideNum; backIndices[num * 18 + 6 * sideNum + 1] = vertexIndex + 5 + sideNum; backIndices[num * 18 + 6 * sideNum + 2] = vertexIndex + 4 + sideNum; // 2. Polygon backIndices[num * 18 + 6 * sideNum + 3] = vertexIndex + 5 + sideNum; backIndices[num * 18 + 6 * sideNum + 4] = vertexIndex + sideNum; backIndices[num * 18 + 6 * sideNum + 5] = vertexIndex + 1 + sideNum; } // for (num) // Go to the next 4 vertices vertexIndex += 4; } // for (num) // Set road back index buffer roadBackIb = new IndexBuffer( BaseGame.Device, typeof(int), backIndices.Length, BufferUsage.WriteOnly); roadBackIb.SetData(backIndices); #endregion #region Generate the road tunnel vertices // Only generate tunnels for the parts were we want to have tunnels for. int totalTunnelLength = 0; foreach (RoadHelperPosition tunnelPos in helperPositions) if (tunnelPos.type == TrackData.RoadHelper.HelperType.Tunnel) totalTunnelLength += 1+(tunnelPos.endNum - tunnelPos.startNum); // Lets use 4 vertices per segment, we could improve that later // by adding more vertices for a round tunnel. roadTunnelVertices = new TangentVertex[totalTunnelLength * 4]; vertexIndex = 0; foreach (RoadHelperPosition tunnelPos in helperPositions) if (tunnelPos.type == TrackData.RoadHelper.HelperType.Tunnel) for (int num = tunnelPos.startNum; num <= tunnelPos.endNum; num++) { // Left side of the road roadTunnelVertices[vertexIndex + 0] = points[num].LeftTangentVertex; roadTunnelVertices[vertexIndex + 0].uv = new Vector2( roadTunnelVertices[vertexIndex + 0].U * RoadTunnelTextureWidthFactor, 0.0f); // Left top side of the road roadTunnelVertices[vertexIndex + 1] = points[num].TunnelTopLeftSideTangentVertex; roadTunnelVertices[vertexIndex + 1].uv = new Vector2( roadTunnelVertices[vertexIndex + 1].U * RoadTunnelTextureWidthFactor, RoadTunnelSideTextureHeight); // Right top side of the road roadTunnelVertices[vertexIndex + 2] = points[num].TunnelTopRightSideTangentVertex; roadTunnelVertices[vertexIndex + 2].uv = new Vector2( roadTunnelVertices[vertexIndex + 2].U * RoadTunnelTextureWidthFactor, 1.0f - RoadTunnelSideTextureHeight); // Right side of the road roadTunnelVertices[vertexIndex + 3] = points[num].RightTangentVertex; roadTunnelVertices[vertexIndex + 3].uv = new Vector2( roadTunnelVertices[vertexIndex + 3].U * RoadTunnelTextureWidthFactor, 1.0f); // Adjust normals for the 2 lower points roadTunnelVertices[vertexIndex + 0].normal *= -1; roadTunnelVertices[vertexIndex + 3].normal *= -1; roadTunnelVertices[vertexIndex + 0].tangent *= -1; roadTunnelVertices[vertexIndex + 3].tangent *= -1; vertexIndex += 4; } // foreach for (num) // Set road back vertex buffer if (roadTunnelVertices.Length > 0) { roadTunnelVb = new VertexBuffer( BaseGame.Device, typeof(TangentVertex), roadTunnelVertices.Length, BufferUsage.WriteOnly); roadTunnelVb.SetData(roadTunnelVertices); // Also calculate all indices, we have 6 polygons for each segment with // 3 vertices each. We got 1 segment less than points because the // last point is duplicated (different tex coords). int totalIndices = 0; foreach (RoadHelperPosition tunnelPos in helperPositions) if (tunnelPos.type == TrackData.RoadHelper.HelperType.Tunnel) totalIndices += (tunnelPos.endNum - tunnelPos.startNum); roadTunnelIndices = new int[totalIndices * 6 * 3]; vertexIndex = 0; int tunnelIndex = 0; foreach (RoadHelperPosition tunnelPos in helperPositions) if (tunnelPos.type == TrackData.RoadHelper.HelperType.Tunnel) { for (int num = tunnelPos.startNum; num < tunnelPos.endNum; num++) { // We only use 4 vertices (and the next 4 vertices), // but we have to construct all 18 indices for our 6 polygons. for (int sideNum = 0; sideNum < 3; sideNum++) { // Each side needs 2 polygons. // Note: This polygons are rendered with culling off because // we want to see the inside and outside of the tunnel. // 1. Polygon roadTunnelIndices[tunnelIndex + 0] = vertexIndex + sideNum; roadTunnelIndices[tunnelIndex + 2] = vertexIndex + 4 + sideNum; roadTunnelIndices[tunnelIndex + 1] = vertexIndex + 5 + sideNum; // 2. Polygon roadTunnelIndices[tunnelIndex + 3] = vertexIndex + 5 + sideNum; roadTunnelIndices[tunnelIndex + 5] = vertexIndex + 1 + sideNum; roadTunnelIndices[tunnelIndex + 4] = vertexIndex + sideNum; tunnelIndex += 6; } // for (sideNum) // Go to the next 4 vertices vertexIndex += 4; } // for (num) // Skip 4 vertices till the next tunnel vertexIndex += 4; } // foreach (tunnelPos) // Set road back index buffer roadTunnelIb = new IndexBuffer( BaseGame.Device, typeof(int), roadTunnelIndices.Length, BufferUsage.WriteOnly); roadTunnelIb.SetData(roadTunnelIndices); } // if #endregion #region Generate guard rails leftRail = new GuardRail(points, GuardRail.Modes.Left, landscape); rightRail = new GuardRail(points, GuardRail.Modes.Right, landscape); #endregion #region Generate columns columns = new TrackColumns(points, landscape); #endregion GenerateObjectsForTrack(landscape); }