/// <summary> /// Creates a new IndexStream object. /// </summary> /// <param name="indices">The list of indices.</param> /// <param name="maxIndex">The maximum index to handle (create IndexStream16 or IndexStream32).</param> /// <returns>The created indexStream.</returns> public static IndexStream Create(IList indices, int maxIndex) { IndexStream stream = IndexStream.Create(indices.Count, maxIndex); for (int i = 0; i < indices.Count; i++) { stream[i] = (int)indices[i]; } return(stream); }
/// <summary> /// copies a source index stream into a certain location of a destination vertex stream /// </summary> /// <param name="source">index stream to take data from</param> /// <param name="sourceIndex">start index</param> /// <param name="dest">index to put data into</param> /// <param name="destIndex">start index</param> /// <param name="length">number of elements</param> /// <param name="vertexOffset">used if vertices are copied to another location</param> public static void Copy(IndexStream source, int sourceIndex, IndexStream dest, int destIndex, int length, int vertexOffset) { if (source.GetType() != dest.GetType() || vertexOffset != 0) { for (int i = 0; i < length; i++) { dest[destIndex] = (ushort)(source[sourceIndex] + vertexOffset); } } else { Array.Copy(source.Data, sourceIndex, dest.Data, destIndex, length); } }
/// <summary> /// creates an indexed vertexUnit and the indexStream from the current vertexUnit /// </summary> /// <param name="vertexUnit">created vertexUnit</param> /// <param name="indexStream">created indexStream</param> public void Indexify(out VertexUnit vertexUnit, out VertexStreams.IndexStream indexStream) { object[] currentVertex = new object[StreamCount]; Hashtable vertices = new Hashtable(); int vertexNum = 0; int currentIndex = 0; indexStream = new VertexStreams.IndexStream16(Size); // TODO: Size is much too high for vertexUnit // calc real size vertexUnit = new VertexUnit(format, Size); for (int i = 0; i < Size; i++) { // fill vertex for (int j = 0; j < StreamCount; j++) { currentVertex[j] = this[j].Data.GetValue(i); } // calc current index if (vertices.Contains(currentVertex)) { currentIndex = (int)vertices[currentVertex]; } else { vertices.Add(currentVertex, vertexNum); currentIndex = vertexNum; vertexNum++; // add new vertex to new streams for (int j = 0; j < StreamCount; j++) { vertexUnit[j].Data.SetValue(currentVertex[j], j); } } indexStream[i] = currentIndex; } }
/// <summary> /// calculate tangent, normal and binormal stream /// Triangle list is assumed for indices format /// there will be a more sophisticated version of this functions for SubSets, which will /// have much similiarity to NVidias MeshMender /// </summary> /// <param name="positions">stream containing vertex positions</param> /// <param name="textures">stream containing texture coordinates</param> /// <param name="indices">stream containing indices</param> /// <returns></returns> public static IGraphicsStream[] CalcTangentSpaceStreams(VertexStreams.PositionStream positions, VertexStreams.TextureStream textures, VertexStreams.IndexStream indices) { // create ret streams VertexStreams.NormalStream normal = new VertexStreams.NormalStream(positions.Size); VertexStreams.TangentStream tangent = new VertexStreams.TangentStream(positions.Size); VertexStreams.BinormalStream binormal = new VertexStreams.BinormalStream(positions.Size); for (int i = 0; i < indices.Size / 3; i++) { // prepare data Vector3 s = Vector3.Zero; Vector3 t = Vector3.Zero; Triangle tri = indices.GetTriangle(i); // calculate s.X and t.X Vector3 a = new Vector3(positions[tri.B].X - positions[tri.A].X, textures[tri.B].X - textures[tri.A].X, textures[tri.B].Y - textures[tri.A].Y); Vector3 b = new Vector3(positions[tri.C].X - positions[tri.A].X, textures[tri.C].X - textures[tri.A].X, textures[tri.C].Y - textures[tri.A].Y); Vector3 axb = Vector3.Cross(a, b); if (Basic.Abs(axb.X) > float.Epsilon) { s.X = -axb.Y / axb.X; t.X = -axb.Z / axb.X; } // calculate s.Y and t.Y a.X = positions[tri.B].Y - positions[tri.A].Y; b.X = positions[tri.C].Y - positions[tri.A].Y; axb = Vector3.Cross(a, b); if (Basic.Abs(axb.X) > float.Epsilon) { s.Y = -axb.Y / axb.X; t.Y = -axb.Z / axb.X; } // calculate s.Z and t.Z a.X = positions[tri.B].Z - positions[tri.A].Z; b.X = positions[tri.C].Z - positions[tri.A].Z; axb = Vector3.Cross(a, b); if (Basic.Abs(axb.X) > float.Epsilon) { s.Z = -axb.Y / axb.X; t.Z = -axb.Z / axb.X; } // normalize and calculate normal vector s.Normalize(); t.Normalize(); // swap t if normal vector of texture space triangle has a negative z direction if (axb.X < float.Epsilon) { t = -t; } Vector3 sxt = Vector3.Unit(Vector3.Cross(s, t)); // add s, t, sxt into the streams // to get the average value - in a later version I will add functionality // to duplicate vertices if the results for one vertex are too different // (like the NVidia MeshMender does ...) tangent[tri.A] += s; tangent[tri.B] += s; tangent[tri.C] += s; binormal[tri.A] += t; binormal[tri.B] += t; binormal[tri.C] += t; normal[tri.A] += sxt; normal[tri.B] += sxt; normal[tri.C] += sxt; } // so last but not least renormalize the summed vectors for (int i = 0; i < positions.Size; i++) { tangent[i].Normalize(); binormal[i].Normalize(); normal[i].Normalize(); } return(new IGraphicsStream[] { tangent, binormal, normal }); }