/// <summary> /// Add all models /// </summary> /// <param name="landscape">Landscape</param> /// <param name="parentMatrix">Parent matrix</param> public void AddAllModels(Landscape landscape, Matrix parentMatrix) { // Just add all models in our combi foreach (CombiObject obj in objects) { landscape.AddObjectToRender(obj.modelName, obj.matrix * parentMatrix, false); } }
/// <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 }
/*now done in track class! * /// <summary> * /// Matrix list for each of the holder pile objects we have to render. * /// </summary> * List<Matrix> holderPileMatrices = new List<Matrix>(); */ #endregion #region Constructor /// <summary> /// Create guard rail /// </summary> /// <param name="points">Points of the road itself</param> /// <param name="mode">Mode, left or right</param> /// <param name="landscape">Landscape</param> public GuardRail(List <TrackVertex> points, Modes mode, Landscape landscape) { #region Generate guardrail points // First generate a list of points at the side of the road where // we are going to generate all the guard rail vertices. // Note: We use only half as much points as points provides! railPoints = new TrackVertex[points.Count / 2 + 1]; for (int num = 0; num < railPoints.Length; num++) { // Make sure we have a closed line, we might have to skip the // last points entry because we devided through 2. int pointNum = num * 2; if (pointNum >= points.Count - 1) { pointNum = points.Count - 1; } // Just copy the points over and manipulate the position and the // right vector depending on which side of the guard rail we are // going to generate here. if (mode == Modes.Left) { railPoints[num] = points[pointNum].LeftTrackVertex; // Invert the direction and right vector for the left side // This makes everything point in the other road direction! railPoints[num].right = -railPoints[num].right; railPoints[num].dir = -railPoints[num].dir; // Move it a little inside the road railPoints[num].pos -= railPoints[num].right * InsideRoadDistance; } // if (mode) else { railPoints[num] = points[pointNum].RightTrackVertex; // Move it a little inside the road railPoints[num].pos -= railPoints[num].right * InsideRoadDistance; } // else } // for (num) #endregion #region Generate vertex buffer railVertices = new TangentVertex[railPoints.Length * GuardRailVertices.Length]; // Current texture coordinate for the guardrail in our current direction. float uTexValue = 0.5f; float lastHolderGap = 0; //HolderGap; for (int num = 0; num < railPoints.Length; num++) { // The unit vectors for our local point space Vector3 right = railPoints[num].right; Vector3 dir = railPoints[num].dir; Vector3 up = railPoints[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; Vector3 localPos = railPoints[num].pos; // Adjust the position for the guardrail, put it up a little. localPos += up * GuardRailHeight; // Set the beginning- or ending point for the guardrail around the // current spline position for (int i = 0; i < GuardRailVertices.Length; i++) { // Transform each of our guardrail points by our local point space // and translate it to our current position. Vector3 pos = Vector3.Transform( GuardRailVertices[i].pos * CorrectionScale, pointSpace * Matrix.CreateTranslation(localPos)); // Also transform our normal and tangent data Vector3 normal = Vector3.TransformNormal( // Left side needs inverted normals (side is inverted) (mode == Modes.Left ? -1 : 1) * GuardRailVertices[i].normal, pointSpace); Vector3 tangent = Vector3.TransformNormal( -GuardRailVertices[i].tangent, //GuardRailVertices[i].normal, //new Vector3(0, 0, -1), pointSpace); // Store vertex railVertices[num * GuardRailVertices.Length + i] = new TangentVertex(pos, uTexValue, GuardRailVertices[i].V, normal, tangent); } // for (int) // Distance of the current position to the next position float distance = Vector3.Distance( railPoints[(num + 1) % railPoints.Length].pos, railPoints[num].pos); // Uniform calculation of the texture coordinates for the guardrail, // so it doesn't matter if there is a gap of 2 or 200 m // -> through "1 / HolderGap" we guarantee that the drilling // (from the texture) is always set in the front of the pile, // no matter which holder gap is set // Note: Only display a holder for every 3 texture loops. uTexValue += (1 / HolderGap) * distance * 2.0f; // Have we reach or go over the holder gap ? if (lastHolderGap - distance <= 0) { // Catmull interpolation, instead the linear interpolation, for a // better position calculation, especially in curves Vector3 p1 = railPoints[num - 1 < 0 ? railPoints.Length - 1 : num - 1].pos; Vector3 p2 = railPoints[num].pos; Vector3 p3 = railPoints[(num + 1) % railPoints.Length].pos; Vector3 p4 = railPoints[(num + 2) % railPoints.Length].pos; Vector3 holderPoint = Vector3.CatmullRom(p1, p2, p3, p4, lastHolderGap / distance); // Store the calculated render matrix for this holder pile object if (landscape != null && // Completely ignore all guard rails for ps1.1 // to save performance (few thousand objects per track less) BaseGame.CanUsePS20 && BaseGame.HighDetail) { landscape.AddObjectToRender( "GuardRailHolder", // Fix scaling a little //Matrix.CreateScale(0.9f) * Matrix.CreateScale(1.125f) * // First the translation to get the pile to the back of the // guardrail and not in the middle Matrix.CreateTranslation(HolderPileCorrectionVector) * // the ordinary transformation to the current point space pointSpace * // at least we calculate to correct position where the pile // reaches exactly the holder gap Matrix.CreateTranslation(holderPoint), // Optimize performance: Set this to false, // but then we won't have shadows for the holder piles. false); //true); } // We have just set a pile, the next pile will be set after // reaching the next holder gap. lastHolderGap += HolderGap; } // if (lastHolderGap) // 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. lastHolderGap -= distance; } // for (num) // Create the vertex buffer from our vertices. railVb = new VertexBuffer( BaseGame.Device, typeof(TangentVertex), railVertices.Length, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic); railVb.SetData(railVertices); #endregion #region GenerateIndexBuffer // Count of quads (polygons) which creates the current guardrail segment int quadPolysPerStrip = GuardRailVertices.Length - 1; int[] indices = new int[(2 * 3 * quadPolysPerStrip) * (railPoints.Length - 1)]; // Current vertex index int vertexIndex = 0; // Helper variable, current index of the indices list int indicesIndex = 0; for (int num = 0; num < railPoints.Length - 1; num++) { // Set all quads of the guardrail for (int j = 0; j < quadPolysPerStrip; j++) { indicesIndex = 3 * 2 * (num * quadPolysPerStrip + j); // 1. Polygon indices[indicesIndex] = vertexIndex + j; indices[indicesIndex + 1] = vertexIndex + 1 + j; indices[indicesIndex + 2] = vertexIndex + 1 + GuardRailVertices.Length + j; // 2. Polygon indices[indicesIndex + 3] = indices[indicesIndex + 2]; indices[indicesIndex + 4] = vertexIndex + GuardRailVertices.Length + j; indices[indicesIndex + 5] = indices[indicesIndex]; } // for (int) vertexIndex += GuardRailVertices.Length; } // for (num) // Create the index buffer from our indices. railIb = new IndexBuffer( BaseGame.Device, typeof(int), indices.Length, ResourceUsage.WriteOnly, ResourceManagementMode.Automatic); railIb.SetData(indices); #endregion } // GuardRail(points, mode, landscape)
private void GenerateTunnelsAndLandscapeObjects( List <TrackData.RoadHelper> roadHelpers, List <TrackData.NeutralObject> neutralObjects, Landscape landscape) { #region Find out where the tunnels are // Go through all tunnel helpers along the road, // everything close enough (<25) is interessting for us. int helperStartedNum = -1; TrackData.RoadHelper.HelperType remType = TrackData.RoadHelper.HelperType.Reset; for (int num = 0; num < points.Count; num++) { Vector3 pos = points[num].pos; foreach (TrackData.RoadHelper roadHelper in roadHelpers) { float dist = Vector3.Distance(roadHelper.pos, pos); if (dist < 25.0f) { if (helperStartedNum >= 0) { helperPositions.Add(new RoadHelperPosition( remType, helperStartedNum, num)); // Reset? if (roadHelper.type == TrackData.RoadHelper.HelperType.Reset) { helperStartedNum = -1; } else { // Start new part helperStartedNum = num; remType = roadHelper.type; } } else { helperStartedNum = num; remType = roadHelper.type; } // Remove this roadHelper (don't use it again)! roadHelpers.Remove(roadHelper); break; } } } // Still a helper open? Then close it close before the end! if (helperStartedNum > 0) { helperPositions.Add(new RoadHelperPosition( remType, helperStartedNum, points.Count - 3)); } #endregion #region Copy over neutral objects for landscape rendering if (landscape != null) { for (int num = 0; num < neutralObjects.Count; num++) { TrackData.NeutralObject obj = neutralObjects[num]; landscape.AddObjectToRender(obj.modelName, obj.matrix, false); } } #endregion }