/// <summary> /// Draw plane vertices /// </summary> private void DrawPlaneVertices() { // Calculate right and dir vectors for constructing the plane. // The following code might look strange, but we have to make sure // that we always get correct up, right and dir vectors. Cross products // can return (0, 0, 0) if the vectors are parallel! Vector3 up = plane.Normal; if (up.Length() == 0) { up = new Vector3(0, 0, 1); } Vector3 helperVec = Vector3.Cross(up, new Vector3(1, 0, 0)); if (helperVec.Length() == 0) { helperVec = new Vector3(0, 1, 0); } Vector3 right = Vector3.Cross(helperVec, up); Vector3 dir = Vector3.Cross(up, right); float dist = plane.D; TangentVertex[] vertices = new TangentVertex[] { // Make plane VERY big and tile texture every 10 meters new TangentVertex( (-right - dir) * size + up * dist, -size / Tiling, -size / Tiling, up, right), new TangentVertex( (-right + dir) * size + up * dist, -size / Tiling, +size / Tiling, up, right), new TangentVertex( (right - dir) * size + up * dist, +size / Tiling, -size / Tiling, up, right), new TangentVertex( (right + dir) * size + up * dist, +size / Tiling, +size / Tiling, up, right), }; // Draw the plane (just 2 simple triangles) BaseGame.Device.DrawUserPrimitives( PrimitiveType.TriangleStrip, vertices, 0, 2); }
/// <summary> /// Create track columns /// </summary> /// <param name="points">Points</param> /// <param name="landscape">Landscape for getting the ground height</param> public TrackColumns(List<TrackVertex> points, Landscape landscape) { if (landscape == null) return; #region Find out column positions float lastColumnsDistance = ColumnsDistance; List<Matrix> columnPointSpacesTop = new List<Matrix>(); List<Matrix> columnPointSpacesBottom = new List<Matrix>(); for (int num = 0; num < points.Count; num++) { // Distance of the current position to the next position float distance = Vector3.Distance( points[(num + 1) % points.Count].pos, points[num].pos); // Uniform calculation of the distance for the columns, // so it doesn't matter if there is a gap of 2 or 200 m // Have we reach or go over the ColumnsDistance? if (lastColumnsDistance - distance <= 0) { // Catmull interpolation, instead the linear interpolation, for a // better position calculation, especially in curves Vector3 p1 = points[num - 1 < 0 ? points.Count - 1 : num - 1].pos; Vector3 p2 = points[num].pos; Vector3 p3 = points[(num + 1) % points.Count].pos; Vector3 p4 = points[(num + 2) % points.Count].pos; Vector3 holderPoint = Vector3.CatmullRom(p1, p2, p3, p4, lastColumnsDistance / distance); // Just find out how much this point is pointing up float draft = Vector3.Dot(points[num].up, new Vector3(0, 0, 1)); // And don't add if height is too small! float columnHeight = holderPoint.Z - landscape.GetMapHeight(holderPoint.X, holderPoint.Y); // Store the position for this holder if (draft > 0.3f &&//< 0 MaxColumnGenerationAngel && columnHeight > MinimumColumnHeight) { columnPositions.Add(holderPoint); // The unit vectors for our local point space Vector3 right = points[num].right; Vector3 dir = points[num].dir; Vector3 up = points[num].up; // Create the coordinate system for the current point by the 3 // unit vectors. Matrix pointSpace = Matrix.Identity; pointSpace.M11 = right.X; pointSpace.M12 = right.Y; pointSpace.M13 = right.Z; pointSpace.M21 = dir.X; pointSpace.M22 = dir.Y; pointSpace.M23 = dir.Z; pointSpace.M31 = up.X; pointSpace.M32 = up.Y; pointSpace.M33 = up.Z; // Remember point space columnPointSpacesTop.Add(pointSpace); // Same for bottom, but don't use up vector (let it stay default) pointSpace = Matrix.Identity; Vector3 upVector = new Vector3(0, 0, 1); // Rebuild right vector (to make it 90 degree to our up vector) Vector3 rightVector = Vector3.Cross(dir, upVector); pointSpace.M11 = rightVector.X; pointSpace.M12 = rightVector.Y; pointSpace.M13 = rightVector.Z; pointSpace.M21 = dir.X; pointSpace.M22 = dir.Y; pointSpace.M23 = dir.Z; columnPointSpacesBottom.Add(pointSpace); } // We have just set a pile, the next pile will be set after // reaching the next holder gap. lastColumnsDistance += ColumnsDistance; } // The distance we have to cover until the next position. // We subtract our current distance from the remaining gap distance, // which will then be checked in the next loop. lastColumnsDistance -= distance; } #endregion #region Generate vertex buffer columnVertices = new TangentVertex[ columnPositions.Count * BaseColumnVertices.Length * 2]; // Go through all columns for (int num = 0; num < columnPositions.Count; num++) { Vector3 pos = columnPositions[num]; // Find out the current landscape height here Vector3 bottomPos = new Vector3(pos.X, pos.Y, landscape.GetMapHeight(pos.X, pos.Y) + ColumnGroundHeight); Vector3 topPos = new Vector3(pos.X, pos.Y, pos.Z - TopColumnSubHeight); // Calculate top v tex coord for this column float topTexV = Vector3.Distance(topPos, bottomPos) / (MathHelper.Pi * 2); // Use the BaseColumnVertices twice, once for the bottom and then for the // top part of our generated column. for (int topBottom = 0; topBottom < 2; topBottom++) { // Go to all BaseColumnVertices for (int i = 0; i < BaseColumnVertices.Length; i++) { int vertIndex = num * BaseColumnVertices.Length * 2 + topBottom * BaseColumnVertices.Length + i; // For the top positions, modify them them to fit directly // on the bottom side of our road. Same for bottom, but don't // modify the z value Matrix transformMatrix = topBottom == 0 ? columnPointSpacesBottom[num] : columnPointSpacesTop[num]; // We don't have to transform the vertices much, just adjust // the z value and the v tex coord. columnVertices[vertIndex] = new TangentVertex( (topBottom == 0 ? bottomPos : topPos) + Vector3.Transform(BaseColumnVertices[i].pos, transformMatrix), BaseColumnVertices[i].U, topBottom == 0 ? 0 : topTexV, Vector3.Transform(BaseColumnVertices[i].normal, transformMatrix), Vector3.Transform(-BaseColumnVertices[i].tangent, transformMatrix)); } } // Also add the bottom position to the list of holders we want // to render later. if (landscape != null && // This is not really required, we can easily optimize this out. BaseGame.HighDetail) landscape.AddObjectToRender( "RoadColumnSegment", new Vector3(bottomPos.X, bottomPos.Y, bottomPos.Z - ColumnGroundHeight)); } // Create the vertex buffer from our vertices. // fix //columnVb = new VertexBuffer( // BaseGame.Device, // typeof(TangentVertex), // columnVertices.Length, // ResourceUsage.WriteOnly, // ResourceManagementMode.Automatic); columnVb = new VertexBuffer( BaseGame.Device, typeof(TangentVertex), columnVertices.Length, BufferUsage.WriteOnly); columnVb.SetData(columnVertices); #endregion #region GenerateIndexBuffer // Count of quads (polygons) we have for each column int quadPolysPerColumn = BaseColumnVertices.Length - 1; int[] indices = new int[(2 * 3 * quadPolysPerColumn) * columnPositions.Count]; // Current vertex index int vertexIndex = 0; // Helper variable, current index of the indices list int indicesIndex = 0; for (int num = 0; num < columnPositions.Count; num++) { // Set all quads of the column for (int j = 0; j < quadPolysPerColumn; j++) { indicesIndex = 3 * 2 * (num * quadPolysPerColumn + j); // 1. Polygon indices[indicesIndex] = vertexIndex + j; indices[indicesIndex + 1] = vertexIndex + 1 + BaseColumnVertices.Length + j; indices[indicesIndex + 2] = vertexIndex + 1 + j; // 2. Polygon indices[indicesIndex + 3] = indices[indicesIndex + 1]; indices[indicesIndex + 4] = indices[indicesIndex]; indices[indicesIndex + 5] = vertexIndex + BaseColumnVertices.Length + j; } // Go to next column vertexIndex += BaseColumnVertices.Length * 2; } // Create the index buffer from our indices. // fix //columnIb = new IndexBuffer( // BaseGame.Device, // typeof(int), // indices.Length, // ResourceUsage.WriteOnly, // ResourceManagementMode.Automatic); columnIb = new IndexBuffer( BaseGame.Device, typeof(int), indices.Length, BufferUsage.WriteOnly); columnIb.SetData(indices); #endregion }
/// <summary> /// Add brake track /// </summary> /// <param name="position">Position</param> /// <param name="dir">Dir vector</param> /// <param name="right">Right vector</param> public void AddBrakeTrack(Vector3 position, Vector3 dir, Vector3 right) { // Just skip if we setting to a similar location again. // This check is much faster and accurate for tracks on top of each // other than the foreach loop below, which is only useful to // put multiple tracks correctly behind each other! if (Vector3.DistanceSquared(position, lastAddedTrackPos) < 0.024f || // Limit number of tracks to keep rendering fast. brakeTracksVertices.Count > MaxBrakeTrackVertices) return; lastAddedTrackPos = position; const float width = 2.4f; // car is 2.6m width, we use 2.4m for tires const float length = 4.5f; // Make brake track 6.5m long float maxDist = (float)Math.Sqrt(width * width + length * length) / 2 - 0.1f; // Check if there is any track already set here or nearby? for (int num = 0; num < brakeTracksVertices.Count; num++) if (Vector3.DistanceSquared(brakeTracksVertices[num].pos, position) < maxDist * maxDist) // Then skip this brake track, don't put that much stuff on // top of each other. return; // Move position a little bit up (above the road) position += new Vector3(0, 0, 0.05f + //0.025f + 0.001f * (brakeTracksVertices.Count % 100)); Vector3 upVector = new Vector3(0, 0, 1); // Just add 6 new vertices to render (2 triangles) TangentVertex[] newVertices = new TangentVertex[] { // First triangle new TangentVertex( position -right*width/2 -dir*length/2, 0, 0, upVector, right), new TangentVertex( position -right*width/2 +dir*length/2, 0, 5, upVector, right), new TangentVertex( position +right*width/2 +dir*length/2, 1, 5, upVector, right), // Second triangle new TangentVertex( position -right*width/2 -dir*length/2, 0, 0, upVector, right), new TangentVertex( position +right*width/2 +dir*length/2, 1, 5, upVector, right), new TangentVertex( position +right*width/2 -dir*length/2, 1, 0, upVector, right), }; brakeTracksVertices.AddRange(newVertices); brakeTracksVerticesArray = brakeTracksVertices.ToArray(); }
/// <summary> /// Draw plane vertices /// </summary> private void DrawPlaneVertices() { // Calculate right and dir vectors for constructing the plane. // The following code might look strange, but we have to make sure // that we always get correct up, right and dir vectors. Cross products // can return (0, 0, 0) if the vectors are parallel! Vector3 up = plane.Normal; if (up.Length() == 0) up = new Vector3(0, 0, 1); Vector3 helperVec = Vector3.Cross(up, new Vector3(1, 0, 0)); if (helperVec.Length() == 0) helperVec = new Vector3(0, 1, 0); Vector3 right = Vector3.Cross(helperVec, up); Vector3 dir = Vector3.Cross(up, right); float dist = plane.D; TangentVertex[] vertices = new TangentVertex[] { // Make plane VERY big and tile texture every 10 meters new TangentVertex( (-right-dir)*size+up*dist, -size/Tiling, -size/Tiling, up, right), new TangentVertex( (-right+dir)*size+up*dist, -size/Tiling, +size/Tiling, up, right), new TangentVertex( (right-dir)*size+up*dist, +size/Tiling, -size/Tiling, up, right), new TangentVertex( (right+dir)*size+up*dist, +size/Tiling, +size/Tiling, up, right), }; // Draw the plane (just 2 simple triangles) BaseGame.Device.DrawUserPrimitives( PrimitiveType.TriangleStrip, vertices, 0, 2); }
/// <summary> /// Add brake track /// </summary> /// <param name="position">Position</param> /// <param name="dir">Dir vector</param> /// <param name="right">Right vector</param> public void AddBrakeTrack(CarPhysics car) { Vector3 position = car.CarPosition + car.CarDirection * 1.25f; // Just skip if we setting to a similar location again. // This check is much faster and accurate for tracks on top of each // other than the foreach loop below, which is only useful to // put multiple tracks correctly behind each other! if (Vector3.DistanceSquared(position, lastAddedTrackPos) < 0.024f || // Limit number of tracks to keep rendering fast. brakeTracksVertices.Count > MaxBrakeTrackVertices) return; lastAddedTrackPos = position; const float width = 2.4f; // car is 2.6m width, we use 2.4m for tires const float length = 4.5f; // Length of break tracks float maxDist = (float)Math.Sqrt(width * width + length * length) / 2 - 0.35f; // Check if there is any track already set here or nearby? for (int num = 0; num < brakeTracksVertices.Count; num++) if (Vector3.DistanceSquared(brakeTracksVertices[num].pos, position) < maxDist * maxDist) // Then skip this brake track, don't put that much stuff on // top of each other. return; // Move position a little bit up (above the road) position += Vector3.Normalize(car.CarUpVector) * RaiseBreakTracksAmount; // Just add 6 new vertices to render (2 triangles) TangentVertex[] newVertices = new TangentVertex[] { // First triangle new TangentVertex( position -car.CarRight*width/2 -car.CarDirection*length/2, 0, 0, car.CarUpVector, car.CarRight), new TangentVertex( position -car.CarRight*width/2 +car.CarDirection*length/2, 0, 5, car.CarUpVector, car.CarRight), new TangentVertex( position +car.CarRight*width/2 +car.CarDirection*length/2, 1, 5, car.CarUpVector, car.CarRight), // Second triangle new TangentVertex( position -car.CarRight*width/2 -car.CarDirection*length/2, 0, 0, car.CarUpVector, car.CarRight), new TangentVertex( position +car.CarRight*width/2 +car.CarDirection*length/2, 1, 5, car.CarUpVector, car.CarRight), new TangentVertex( position +car.CarRight*width/2 -car.CarDirection*length/2, 1, 0, car.CarUpVector, car.CarRight), }; brakeTracksVertices.AddRange(newVertices); brakeTracksVerticesArray = brakeTracksVertices.ToArray(); }