public static void ComputeTangent(ref VertexPNTTB srcVert, VertexPNTTB vert1, VertexPNTTB vert2) { Vector4 d0 = vert1.Position - srcVert.Position; Vector4 d1 = vert2.Position - srcVert.Position; Vector2 s = vert1.Texcoord - srcVert.Texcoord; Vector2 t = vert2.Texcoord - srcVert.Texcoord; float r = 1.0F / (t.X * s.Y - t.Y * s.X); Vector3 tangent = new Vector3(s.Y * d1.X - t.Y * d0.X, s.Y * d1.Y - t.Y * d0.Y, s.Y * d1.Z - t.Y * d0.Z) * r; srcVert.Tangent = Vector3.Normalize(tangent - srcVert.Normal * Vector3.Dot(srcVert.Normal, tangent)); }
void ParseSMDTriangles(StreamReader file) { if (this.modelGroups != null) return; SortedList<string, List<VertexPNTTB>> vertexLists = new SortedList<string, List<VertexPNTTB>>(); SortedList<string, List<ushort>> indicesList = new SortedList<string, List<ushort>>(); while (!file.EndOfStream) { string text = file.ReadLine(); if (text == "end") { break; } string materialName = text.Split('.')[0]; if (!vertexLists.ContainsKey(materialName)) { vertexLists.Add(materialName, new List<VertexPNTTB>()); indicesList.Add(materialName, new List<ushort>()); } VertexPNTTB[] vertices = new VertexPNTTB[3]; for (int i = 0; i < 3; i++) { text = file.ReadLine(); string[] data = text.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); Vector4 bone = new Vector4(int.Parse(data[0]), 0, 0, 0); Vector4 boneWeights = new Vector4(1.0f, 0, 0, 0); Vector3 pos; pos.X = float.Parse(data[1]); pos.Y = float.Parse(data[2]); pos.Z = float.Parse(data[3]); Vector3 normal; normal.X = float.Parse(data[4]); normal.Y = float.Parse(data[5]); normal.Z = float.Parse(data[6]); normal.Normalize(); Vector2 texcoord; texcoord.X = float.Parse(data[7]); texcoord.Y = float.Parse(data[8]); if (data.Length > 10) //Code for multiple blendweights { int boneBlendCount = int.Parse(data[9]); for (int m = 0; m < boneBlendCount; m++) { int index = m * 2 + 10; switch (m) { case 0: bone.Y = int.Parse(data[index]); boneWeights.Y = float.Parse(data[index + 1]); break; case 1: bone.Z = int.Parse(data[index]); boneWeights.Z = float.Parse(data[index + 1]); break; case 2: bone.W = int.Parse(data[index]); boneWeights.W = float.Parse(data[index + 1]); break; } } float sum = Vector4.Dot(boneWeights, Vector4.One); boneWeights.X = 1.0f - sum; } vertices[i] = new VertexPNTTB(pos, normal, texcoord, bone, boneWeights, Vector3.Zero); indicesList[materialName].Add((ushort)(vertexLists[materialName].Count+i)); } //Compute our tangent vectors MathUtils.ComputeTangent(ref vertices[0], vertices[1], vertices[2]); MathUtils.ComputeTangent(ref vertices[1], vertices[2], vertices[0]); MathUtils.ComputeTangent(ref vertices[2], vertices[0], vertices[1]); vertexLists[materialName].AddRange(vertices); } this.modelGroups = new ModelPart[vertexLists.Keys.Count]; for (int i = 0; i < vertexLists.Keys.Count; i++) { string key = vertexLists.Keys[i]; VertexBuffer vertexBuffer = new VertexBuffer(GFX.Device, vertexLists[key].Count * VertexPNTTB.SizeInBytes, BufferUsage.WriteOnly); vertexBuffer.SetData<VertexPNTTB>(vertexLists[key].ToArray()); IndexBuffer indexBuffer = new IndexBuffer(GFX.Device, sizeof(ushort) * indicesList[key].Count, BufferUsage.WriteOnly, IndexElementSize.SixteenBits); indexBuffer.SetData<ushort>(indicesList[key].ToArray()); Vector3 pos = new Vector3(vertexLists[key][0].Position.X, vertexLists[key][0].Position.Y, vertexLists[key][0].Position.Z); BoundingBox bounds = new BoundingBox(pos, pos); for (int j = 0; j < vertexLists[key].Count; j++) { pos = new Vector3(vertexLists[key][j].Position.X, vertexLists[key][j].Position.Y, vertexLists[key][j].Position.Z); bounds.Max = Vector3.Max(bounds.Max, pos); bounds.Min = Vector3.Min(bounds.Min, pos); } modelGroups[i] = new ModelPart(key, vertexBuffer, indexBuffer, bounds); } }