private static void CalculateNormals(List <STVertex> vertices, List <uint> f) { if (vertices.Count < 3) { return; } Vector3[] normals = new Vector3[vertices.Count]; for (int i = 0; i < normals.Length; i++) { normals[i] = new Vector3(0, 0, 0); } for (int i = 0; i < f.Count; i += 3) { STVertex v1 = vertices[(int)f[i]]; STVertex v2 = vertices[(int)f[i + 1]]; STVertex v3 = vertices[(int)f[i + 2]]; Vector3 nrm = CalculateNormal(v1, v2, v3); normals[f[i + 0]] += nrm * (nrm.Length / 2); normals[f[i + 1]] += nrm * (nrm.Length / 2); normals[f[i + 2]] += nrm * (nrm.Length / 2); } for (int i = 0; i < normals.Length; i++) { vertices[i].Normal = normals[i].Normalized(); } }
private static STVertex ReadLayout3(this FileReader reader, uint hash) { uint stride = GetStride(hash); STVertex vertex = new STVertex(); vertex.TexCoords = new Vector2[2]; if (stride >= 0x1C) { vertex.Colors = new Vector4[1]; } vertex.Position = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); vertex.Normal = new Vector3( reader.ReadSByte() / 255f, reader.ReadSByte() / 255f, reader.ReadSByte() / 255f).Normalized(); reader.ReadSByte(); vertex.TexCoords[0] = new Vector2( reader.ReadInt16() / 1024.0f, reader.ReadInt16() / 1024.0f); vertex.TexCoords[1] = new Vector2( reader.ReadInt16() / 1024.0f, reader.ReadInt16() / 1024.0f); if (stride >= 0x1C) { vertex.Colors[0] = new Vector4( reader.ReadByte() / 255.0f, reader.ReadByte() / 255.0f, reader.ReadByte() / 255.0f, reader.ReadByte() / 255.0f); } return(vertex); }
public Dictionary <string, KeyGroup> LoadKeyGroups() { //Load the vertex buffer into the helper to easily access the data. VertexBufferHelper helper = new VertexBufferHelper(VertexBuffer, ParentFile.ByteOrder); int index = 0; Dictionary <string, KeyGroup> keyGroups = new Dictionary <string, KeyGroup>(); foreach (var keyShape in Shape.KeyShapes) { var group = new KeyGroup(); //Loop through all the vertex data and load it into our vertex data group.Vertices = new List <STVertex>(); //Get all the necessary attributes var positions = TryGetValues(helper, $"_p{index}"); for (int i = 0; i < positions.Length; i++) { var vertex = new STVertex(); vertex.Position = new Vector3(positions[i].X, positions[i].Y, positions[i].Z); group.Vertices.Add(vertex); } if (group.Vertices.Count > 0) { keyGroups.Add(keyShape.Key, group); } index++; } return(keyGroups); }
public STGenericModel ToGeneric() { if (Model != null) { return(Model); } var model = new STGenericModel(FileInfo.FileName); /* var msh = new STGenericMesh() { Name = $"Mesh0" }; * model.Meshes.Add(msh); * * List<STVertex> verts = new List<STVertex>(); * for (int v = 0; v < MorphData.Positions.Count; v++) * { * STVertex vertex = new STVertex(); * vertex.Position = MorphData.Positions[v]; * verts.Add(vertex); * } * * STPolygonGroup group = new STPolygonGroup(); * group.PrimitiveType = STPrimitiveType.Points; * msh.PolygonGroups.Add(group); * * msh.Vertices.AddRange(verts); * msh.Optmize(group); */ for (int i = 0; i < MorphData.MorphGroups.Count; i++) { var mesh = new STGenericMesh() { Name = $"Mesh{i}" }; model.Meshes.Add(mesh); var morphData = MorphData.MorphGroups[i]; STPolygonGroup group = new STPolygonGroup(); group.PrimitiveType = STPrimitiveType.Triangles; mesh.PolygonGroups.Add(group); List <STVertex> verts = new List <STVertex>(); for (int v = 0; v < morphData.Positions.Count; v++) { STVertex vertex = new STVertex(); vertex.Position = morphData.Positions[v]; verts.Add(vertex); } verts = ConvertTriStrips(verts); mesh.Vertices.AddRange(verts); mesh.Optmize(group); } Model = model; return(model); }
private static Vector3 CalculateNormal(STVertex v1, STVertex v2, STVertex v3) { Vector3 U = v2.Position - v1.Position; Vector3 V = v3.Position - v1.Position; // Don't normalize here, so surface area can be calculated. return(Vector3.Cross(U, V)); }
private static STVertex ReadLayout4(this FileReader reader, uint hash) { uint stride = GetStride(hash); STVertex vertex = new STVertex(); vertex.Position = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); return(vertex); }
private static STVertex ReadLayout1(this FileReader reader, uint hash) { uint stride = GetStride(hash); STVertex vertex = new STVertex(); vertex.TexCoords = new Vector2[1]; long pos = reader.Position; vertex.Position = new Vector3( UShortToFloatDecode(reader.ReadInt16()), UShortToFloatDecode(reader.ReadInt16()), UShortToFloatDecode(reader.ReadInt16())); vertex.Normal = new Vector3( reader.ReadSByte() / 255f, reader.ReadSByte() / 255f, reader.ReadSByte() / 255f); byte boneIndex1 = reader.ReadByte(); vertex.TexCoords[0] = new Vector2( reader.ReadInt16() / 1024.0f, reader.ReadInt16() / 1024.0f); if (stride >= 22) { byte boneIndex2 = reader.ReadByte(); byte boneIndex3 = reader.ReadByte(); ushort[] weights = reader.ReadUInt16s(3); vertex.BoneIndices.Add(boneIndex2 / 3); vertex.BoneIndices.Add(boneIndex3 / 3); if (weights[2] != 0) { vertex.BoneIndices.Add(boneIndex1 / 3); } vertex.BoneWeights.Add(weights[0] / 16384.0f); vertex.BoneWeights.Add(weights[1] / 16384.0f); if (weights[2] != 0) { vertex.BoneWeights.Add(weights[2] / 16384.0f); } } if (stride == 26) { } return(vertex); }
//Geometry shader effects ie uvslidingmaterialgs. private static STVertex ReadLayout6(this FileReader reader, uint hash) { //This requires geoemtry shader so skip it atm return(new STVertex()); uint stride = GetStride(hash); STVertex vertex = new STVertex(); vertex.TexCoords = new Vector2[1]; vertex.Position = new Vector3( reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle()); return(vertex); }
public static List <STVertex> ReadDisplayLists(Stream stream, Stream dataStream, GXVertexLayout[] layouts, Config config = null, ushort[] matrixIndices = null) { if (config == null) { config = new Config(); } int numColors = GetColorCount(layouts); int numTexCoords = GetTexCoordsCount(layouts); bool hasVertexColors = layouts.Any(x => x.Attribute == GXAttributes.Color0); List <GXOpCodes> operations = new List <GXOpCodes>(); List <STVertex> vertices = new List <STVertex>(); using (var dataReader = new FileReader(dataStream, true)) using (var reader = new FileReader(stream, true)) { dataReader.SetByteOrder(true); reader.SetByteOrder(true); while (!reader.EndOfStream) { GXOpCodes opCode = (GXOpCodes)(reader.ReadByte()); if (opCode == GXOpCodes.NOOP) { continue; } opCode = (GXOpCodes)((byte)opCode + config.OpCodeShift); if (!operations.Contains(opCode)) { operations.Add(opCode); } List <STVertex> verts = new List <STVertex>(); ushort numVertices = reader.ReadUInt16(); for (int v = 0; v < numVertices; v++) { STVertex vertex = new STVertex(); vertex.TexCoords = new OpenTK.Vector2[numTexCoords]; if (hasVertexColors) { vertex.Colors = new OpenTK.Vector4[numColors]; } for (int l = 0; l < layouts.Length; l++) { var index = ReadLayout(reader, layouts[l]); ParseData(vertex, dataReader, layouts[l], index, matrixIndices); } verts.Add(vertex); } if (opCode == GXOpCodes.DRAW_TRIANGLES) { vertices.AddRange(verts); } else if (opCode == GXOpCodes.DRAW_TRIANGLE_FAN) { verts = ConvertTriFans(verts); vertices.AddRange(verts); } else if (opCode == GXOpCodes.DRAW_TRIANGLE_STRIP) { verts = ConvertTriStrips(verts); vertices.AddRange(verts); } else if (opCode == GXOpCodes.DRAW_QUADS || opCode == GXOpCodes.DRAW_QUADS_2) { verts = ConvertQuads(verts); vertices.AddRange(verts); } else { Console.WriteLine($"Unknown opCode {opCode}"); vertices.AddRange(verts); } } } operations.Clear(); return(vertices); }
private static void ParseData(STVertex vertex, FileReader dataReader, GXVertexLayout layout, int index, ushort[] matrixIndices) { int numElements = GetElementCount(layout.Attribute); int stride = GetDataStride(layout.CompType) * numElements; if (IsColor(layout)) { stride = GetColorDataStride(layout.CompType); } using (dataReader.TemporarySeek(layout.DataOffset + (index * stride), SeekOrigin.Begin)) { // Console.WriteLine($"attribute {layout.Attribute} stride {stride} index {index}"); switch (layout.Attribute) { case GXAttributes.Position: { float X = ReadDataLayout(dataReader, layout); float Y = ReadDataLayout(dataReader, layout); float Z = ReadDataLayout(dataReader, layout); vertex.Position = new OpenTK.Vector3(X, Y, Z); } break; case GXAttributes.Normal: { float X = ReadDataLayout(dataReader, layout); float Y = ReadDataLayout(dataReader, layout); float Z = ReadDataLayout(dataReader, layout); vertex.Normal = new OpenTK.Vector3(X, Y, Z).Normalized(); } break; case GXAttributes.NormalBinormalTangent: { float NormalX = ReadDataLayout(dataReader, layout); float NormalY = ReadDataLayout(dataReader, layout); float NormalZ = ReadDataLayout(dataReader, layout); float BinormalX = ReadDataLayout(dataReader, layout); float BinormalY = ReadDataLayout(dataReader, layout); float BinormalZ = ReadDataLayout(dataReader, layout); float TangentX = ReadDataLayout(dataReader, layout); float TangentY = ReadDataLayout(dataReader, layout); float TangentZ = ReadDataLayout(dataReader, layout); vertex.Normal = new OpenTK.Vector3(NormalX, NormalY, NormalZ).Normalized(); vertex.Bitangent = new OpenTK.Vector4(BinormalX, BinormalY, BinormalZ, 1); vertex.Tangent = new OpenTK.Vector4(TangentX, TangentY, TangentZ, 1); } break; case GXAttributes.TexCoord0: case GXAttributes.TexCoord1: case GXAttributes.TexCoord2: case GXAttributes.TexCoord3: case GXAttributes.TexCoord4: case GXAttributes.TexCoord5: case GXAttributes.TexCoord6: case GXAttributes.TexCoord7: { int channel = GetChannel(layout.Attribute); float X = ReadDataLayout(dataReader, layout); float Y = ReadDataLayout(dataReader, layout); vertex.TexCoords[channel] = new OpenTK.Vector2(X, Y); } break; case GXAttributes.Color0: case GXAttributes.Color1: { int channel = GetChannel(layout.Attribute); var color = ReadDataColorLayout(dataReader, layout); vertex.Colors[0] = new OpenTK.Vector4(color.X, color.Y, color.Z, color.W); } break; case GXAttributes.PosNormMatrix: { if (index != -1) { int boneID = index / 3; if (matrixIndices != null) { boneID = matrixIndices[index / 3]; } Console.WriteLine($"BONEID {index} real {boneID}"); vertex.BoneIndices.Add(boneID); vertex.BoneWeights.Add(1.0f); } } break; } } }
private static void ParseData(STVertex vertex, FileReader dataReader, GXVertexLayout layout, int index) { int numElements = GetElementCount(layout.Attribute); int stride = GetDataStride(layout.CompType) * numElements; if (IsColor(layout)) { stride = GetColorDataStride(layout.CompType); } using (dataReader.TemporarySeek(layout.DataOffset + (index * stride), SeekOrigin.Begin)) { // Console.WriteLine($"attribute {layout.Attribute} stride {stride} index {index}"); switch (layout.Attribute) { case GXAttributes.Position: { float X = ReadDataLayout(dataReader, layout); float Y = ReadDataLayout(dataReader, layout); float Z = ReadDataLayout(dataReader, layout); vertex.Position = new OpenTK.Vector3(X, Y, Z); } break; case GXAttributes.Normal: { float X = ReadDataLayout(dataReader, layout); float Y = ReadDataLayout(dataReader, layout); float Z = ReadDataLayout(dataReader, layout); vertex.Normal = new OpenTK.Vector3(X, Y, Z).Normalized(); } break; case GXAttributes.TexCoord0: case GXAttributes.TexCoord1: case GXAttributes.TexCoord2: case GXAttributes.TexCoord3: case GXAttributes.TexCoord4: case GXAttributes.TexCoord5: case GXAttributes.TexCoord6: case GXAttributes.TexCoord7: { int channel = (int)(layout.Attribute - GXAttributes.TexCoord0); float X = ReadDataLayout(dataReader, layout); float Y = ReadDataLayout(dataReader, layout); vertex.TexCoords[0] = new OpenTK.Vector2(X, Y); } break; case GXAttributes.Color0: case GXAttributes.Color1: { int channel = (int)(layout.Attribute - GXAttributes.Color0); var color = ReadDataColorLayout(dataReader, layout); vertex.Colors[0] = new OpenTK.Vector4(color.X, color.Y, color.Z, color.W); } break; case GXAttributes.PosNormMatrix: { if (index != -1) { int boneID = index / 3; vertex.BoneIndices.Add(boneID); vertex.BoneWeights.Add(1.0f); } } break; } } }
public STGenericModel ToGeneric() { if (Model != null) { return(Model); } var model = new STGenericModel(FileInfo.FileName); var sectionData = Header.FileHeader.SectionData; foreach (var bone in sectionData.SkeletonChunk.Bones) { model.Skeleton.Bones.Add(new STBone(model.Skeleton) { Name = $"Bone{bone.ID}", Position = new Vector3( bone.Translation.X, bone.Translation.Y, bone.Translation.Z), Scale = new Vector3( bone.Scale.X, bone.Scale.Y, bone.Scale.Z), EulerRotation = new Vector3( bone.Rotation.X, bone.Rotation.Y, bone.Rotation.Z), ParentIndex = bone.ParentIndex, }); } model.Skeleton.Reset(); model.Skeleton.Update(); foreach (var tex in sectionData.TextureChunk.Textures) { model.Textures.Add(new CTXB.TextureWrapper(tex) { Name = $"Texture{model.Textures.Count}" }); } foreach (var mat in sectionData.MaterialChunk.Materials) { STGenericMaterial genericMat = new STGenericMaterial(); genericMat.Name = $"Material{model.Materials.Count}"; model.Materials.Add(genericMat); bool HasDiffuse = false; foreach (var tex in mat.TextureMaps) { if (tex.TextureIndex != -1) { STGenericTextureMap matTexture = new STGenericTextureMap(); genericMat.TextureMaps.Add(matTexture); if (tex.TextureIndex < model.Textures.Count) { matTexture.Name = model.Textures[tex.TextureIndex].Name; } if (!HasDiffuse && matTexture.Name != "bg_syadowmap") //Quick hack till i do texture env stuff { matTexture.Type = STTextureType.Diffuse; HasDiffuse = true; } } } } var shapeData = sectionData.SkeletalMeshChunk.ShapeChunk; var meshData = sectionData.SkeletalMeshChunk.MeshChunk; foreach (var mesh in meshData.Meshes) { STGenericMesh genericMesh = new STGenericMesh(); genericMesh.Name = $"Mesh_{model.Meshes.Count}"; model.Meshes.Add(genericMesh); var shape = shapeData.SeperateShapes[(int)mesh.SepdIndex]; List <ushort> SkinnedBoneTable = new List <ushort>(); foreach (var prim in shape.Primatives) { if (prim.BoneIndexTable != null) { SkinnedBoneTable.AddRange(prim.BoneIndexTable); } } //Now load the vertex and face data if (shape.Position.VertexData != null) { int VertexCount = shape.Position.VertexData.Length; for (int v = 0; v < VertexCount; v++) { STVertex vert = new STVertex(); vert.TexCoords = new Vector2[1]; vert.Position = new OpenTK.Vector3( shape.Position.VertexData[v].X, shape.Position.VertexData[v].Y, shape.Position.VertexData[v].Z); if (shape.Normal.VertexData != null && shape.Normal.VertexData.Length > v) { vert.Normal = new OpenTK.Vector3( shape.Normal.VertexData[v].X, shape.Normal.VertexData[v].Y, shape.Normal.VertexData[v].Z).Normalized(); } if (shape.Color.VertexData != null && shape.Color.VertexData.Length > v) { vert.Colors = new Vector4[1] { new OpenTK.Vector4( shape.Color.VertexData[v].X, shape.Color.VertexData[v].Y, shape.Color.VertexData[v].Z, shape.Color.VertexData[v].W).Normalized() }; } if (shape.TexCoord0.VertexData != null && shape.TexCoord0.VertexData.Length > v) { vert.TexCoords[0] = new OpenTK.Vector2( shape.TexCoord0.VertexData[v].X, 1 - shape.TexCoord0.VertexData[v].Y); } if (shape.TexCoord1.VertexData != null) { } if (shape.TexCoord2.VertexData != null) { } for (int i = 0; i < 16; i++) { if (i < shape.Primatives[0].BoneIndexTable.Length) { int boneId = shape.Primatives[0].BoneIndexTable[i]; if (shape.Primatives[0].SkinningMode == SkinningMode.RIGID_SKINNING) { vert.Position = Vector3.TransformPosition(vert.Position, model.Skeleton.Bones[boneId].Transform); vert.Normal = Vector3.TransformNormal(vert.Position, model.Skeleton.Bones[boneId].Transform); } } } bool HasSkinning = shape.Primatives[0].SkinningMode != SkinningMode.SINGLE_BONE && shape.BoneIndices.Type == CmbDataType.UByte; //Noclip checks the type for ubyte so do the same bool HasWeights = shape.Primatives[0].SkinningMode == SkinningMode.SMOOTH_SKINNING; if (shape.BoneIndices.VertexData != null && HasSkinning && shape.BoneIndices.VertexData.Length > v) { var BoneIndices = shape.BoneIndices.VertexData[v]; for (int j = 0; j < shape.boneDimension; j++) { if (BoneIndices[j] < SkinnedBoneTable.Count) { vert.BoneIndices.Add((int)SkinnedBoneTable[(int)BoneIndices[j]]); } // Console.WriteLine("boneIds " + BoneIndices[j]); // ushort index = shape.Primatives[0].BoneIndexTable[(uint)BoneIndices[j]]; } } if (shape.BoneWeights.VertexData != null && HasWeights && shape.BoneWeights.VertexData.Length > v) { var BoneWeights = shape.BoneWeights.VertexData[v]; for (int j = 0; j < shape.boneDimension; j++) { vert.BoneWeights.Add(BoneWeights[j]); } } genericMesh.Vertices.Add(vert); } } foreach (var prim in shape.Primatives) { STPolygonGroup group = new STPolygonGroup(); genericMesh.PolygonGroups.Add(group); group.MaterialIndex = mesh.MaterialIndex; // for (int i = 0; i < prim.Primatives[0].Indices.Length; i++) // group.Faces.Add(prim.Primatives[0].Indices[i]); } } Model = model; return(model); }
private static void ParseVertexSource(ref STVertex vertex, ColladaScene scene, source source, int numTexCoordChannels, int numColorChannels, int stride, int index, int set, string semantic) { float_array array = source.Item as float_array; switch (semantic) { case "VERTEX": case "POSITION": vertex.Position = new Vector3( (float)array.Values[index + 0], (float)array.Values[index + 1], (float)array.Values[index + 2]); vertex.Position = ApplyUintScaling(scene, vertex.Position); if (scene.UpAxisType == UpAxisType.Z_UP) { vertex.Position = new Vector3( vertex.Position.X, vertex.Position.Z, -vertex.Position.Y); } break; case "NORMAL": vertex.Normal = new Vector3( (float)array.Values[index + 0], (float)array.Values[index + 1], (float)array.Values[index + 2]); if (scene.UpAxisType == UpAxisType.Z_UP) { vertex.Normal = new Vector3( vertex.Normal.X, vertex.Normal.Z, -vertex.Normal.Y); } break; case "TEXCOORD": vertex.TexCoords[set] = new Vector2( (float)array.Values[index + 0], (float)array.Values[index + 1]); break; case "COLOR": float R = 1, G = 1, B = 1, A = 1; if (stride >= 1) { R = (float)array.Values[index + 0]; } if (stride >= 2) { G = (float)array.Values[index + 1]; } if (stride >= 3) { B = (float)array.Values[index + 2]; } if (stride >= 4) { A = (float)array.Values[index + 3]; } vertex.Colors[set] = new Vector4(R, G, B, A); break; } //We need to make sure the axis is converted to Z up /* switch (scene.UpAxisType) * { * case UpAxisType.X_UP: * break; * case UpAxisType.Y_UP: * Vector3 pos = vertex.Position; * Vector3 nrm = vertex.Normal; * // vertex.Position = new Vector3(pos.X, pos.Z, pos.Y); * // vertex.Normal = new Vector3(nrm.X, nrm.Z, nrm.Y); * break; * }*/ }
private static void ConvertPolygon(ColladaScene scene, STGenericMesh mesh, mesh daeMesh, InputLocalOffset[] inputs, List <BoneWeight[]> boneWeights, library_materials materials, string material, string polys, int polyCount, string vcount = "") { List <uint> faces = new List <uint>(); STPolygonGroup group = new STPolygonGroup(); mesh.PolygonGroups.Add(group); group.MaterialIndex = DaeUtility.FindMaterialIndex(materials, material); string[] indices = polys.Trim(' ').Split(' '); string[] vertexCount = new string[0]; if (vcount != string.Empty) { vertexCount = vcount.Trim(' ').Split(' '); } int stride = 0; for (int i = 0; i < inputs.Length; i++) { stride = Math.Max(0, (int)inputs[i].offset + 1); } //Create a current list of all the vertices //Use a list to expand duplicate indices List <Vertex> vertices = new List <Vertex>(); var vertexSource = DaeUtility.FindSourceFromInput(daeMesh.vertices.input[0], daeMesh.source); var floatArr = vertexSource.Item as float_array; for (int v = 0; v < (int)floatArr.count / 3; v++) { vertices.Add(new Vertex(vertices.Count, new List <int>())); } var indexStride = (indices.Length / 3) / polyCount; for (int i = 0; i < polyCount; i++) { int count = 3; if (vertexCount.Length > i) { count = Convert.ToInt32(vertexCount[i]); } for (int v = 0; v < count; v++) { List <int> semanticIndices = new List <int>(); for (int j = 0; j < inputs.Length; j++) { int faceOffset = (indexStride * 3) * i; int index = Convert.ToInt32(indices[faceOffset + (v * indexStride) + (int)inputs[j].offset]); semanticIndices.Add(index); } BoneWeight[] boneWeightData = new BoneWeight[0]; if (boneWeights?.Count > semanticIndices[0]) { boneWeightData = boneWeights[semanticIndices[0]]; } VertexLoader.LoadVertex(ref faces, ref vertices, semanticIndices, boneWeightData); } } int numTexCoordChannels = 0; int numColorChannels = 0; //Find them in both types of inputs for (int i = 0; i < inputs.Length; i++) { if (inputs[i].semantic == "TEXCOORD") { numTexCoordChannels++; } if (inputs[i].semantic == "COLOR") { numColorChannels++; } } for (int i = 0; i < daeMesh.vertices.input.Length; i++) { if (daeMesh.vertices.input[i].semantic == "TEXCOORD") { numTexCoordChannels++; } if (daeMesh.vertices.input[i].semantic == "COLOR") { numColorChannels++; } } for (int i = 0; i < vertices.Count; i++) { if (!vertices[i].IsSet) { vertices.Remove(vertices[i]); } } bool hasNormals = false; foreach (var daeVertex in vertices) { if (daeVertex.semanticIndices.Count == 0) { continue; } STVertex vertex = new STVertex(); vertex.TexCoords = new Vector2[numTexCoordChannels]; vertex.Colors = new Vector4[numColorChannels]; vertex.BoneWeights = daeVertex.BoneWeights.ToList(); mesh.Vertices.Add(vertex); //DAE has 2 inputs. Vertex and triangle inputs //Triangle inputs use indices over vertex inputs which only use one //Triangle inputs allow multiple color/uv sets unlike vertex inputs //Certain programs ie Noesis DAEs use vertex inputs. Most programs use triangle inputs for (int j = 0; j < daeMesh.vertices.input.Length; j++) { //Vertex inputs only use the first index var vertexInput = daeMesh.vertices.input[j]; source source = DaeUtility.FindSourceFromInput(vertexInput, daeMesh.source); if (source == null) { continue; } if (vertexInput.semantic == "NORMAL") { hasNormals = true; } int dataStride = (int)source.technique_common.accessor.stride; int index = daeVertex.semanticIndices[0] * dataStride; ParseVertexSource(ref vertex, scene, source, numTexCoordChannels, numColorChannels, dataStride, index, 0, vertexInput.semantic); } for (int i = 0; i < inputs.Length; i++) { var input = inputs[i]; source source = DaeUtility.FindSourceFromInput(input, daeMesh.source); if (source == null) { continue; } if (input.semantic == "NORMAL") { hasNormals = true; } int dataStride = (int)source.technique_common.accessor.stride; int index = daeVertex.semanticIndices[i] * dataStride; ParseVertexSource(ref vertex, scene, source, numTexCoordChannels, numColorChannels, dataStride, index, (int)input.set, input.semantic); } } group.Faces = faces; if (!hasNormals) { CalculateNormals(mesh.Vertices, faces); } if (scene.Settings.RemoveDuplicateVerts) { RemoveDuplicateVerts(mesh.Vertices, faces); } }
/// <summary> /// Updates the current buffer from the shapes vertex buffer data. /// </summary> public void UpdateVertexBuffer(bool weighPositions = false) { //Load the vertex buffer into the helper to easily access the data. VertexBufferHelper helper = new VertexBufferHelper(VertexBuffer, ParentFile.ByteOrder); //Loop through all the vertex data and load it into our vertex data Vertices = new List <STVertex>(); //Get all the necessary attributes var positions = TryGetValues(helper, "_p0"); var normals = TryGetValues(helper, "_n0"); var texCoords = TryGetChannelValues(helper, "_u"); var colors = TryGetChannelValues(helper, "_c"); var tangents = TryGetValues(helper, "_t0"); var bitangents = TryGetValues(helper, "_b0"); var weights0 = TryGetValues(helper, "_w0"); var indices0 = TryGetValues(helper, "_i0"); var weights1 = TryGetValues(helper, "_w1"); var indices1 = TryGetValues(helper, "_i1"); var boneIndexList = ParentSkeleton.Skeleton.MatrixToBoneList; float scale = GLFrameworkEngine.GLContext.PreviewScale; //Get the position attribute and use the length for the vertex count for (int v = 0; v < positions.Length; v++) { STVertex vertex = new STVertex(); Vertices.Add(vertex); vertex.Position = new Vector3(positions[v].X, positions[v].Y, positions[v].Z) * scale; if (normals.Length > 0) { vertex.Normal = new Vector3(normals[v].X, normals[v].Y, normals[v].Z); } if (texCoords.Length > 0) { vertex.TexCoords = new Vector2[texCoords.Length]; for (int i = 0; i < texCoords.Length; i++) { vertex.TexCoords[i] = new Vector2(texCoords[i][v].X, texCoords[i][v].Y); } } if (colors.Length > 0) { vertex.Colors = new Vector4[colors.Length]; for (int i = 0; i < colors.Length; i++) { vertex.Colors[i] = new Vector4( colors[i][v].X, colors[i][v].Y, colors[i][v].Z, colors[i][v].W); } } if (tangents.Length > 0) { vertex.Tangent = new Vector4(tangents[v].X, tangents[v].Y, tangents[v].Z, tangents[v].W); } if (bitangents.Length > 0) { vertex.Bitangent = new Vector4(bitangents[v].X, bitangents[v].Y, bitangents[v].Z, bitangents[v].W); } if (VertexSkinCount == 0 && weighPositions) { var bone = ParentSkeleton.Bones[Shape.BoneIndex]; vertex.Position = Vector3.TransformPosition(vertex.Position, bone.Transform); vertex.Normal = Vector3.TransformNormal(vertex.Normal, bone.Transform); } for (int i = 0; i < VertexBuffer.VertexSkinCount; i++) { int index = -1; float weight = 0.0f; if (i > 3 && indices1.Length > 0) { index = boneIndexList[(int)indices1[v][i - 4]]; weight = weights1.Length > 0 ? weights1[v][i - 4] : 1.0f; } else if (i <= 3) { index = boneIndexList[(int)indices0[v][i]]; weight = weights0.Length > 0 ? weights0[v][i] : 1.0f; } else { break; } vertex.BoneIndices.Add(index); vertex.BoneWeights.Add(weight); if (VertexSkinCount == 1 && weighPositions) { var bone = ParentSkeleton.Bones[index]; vertex.Position = Vector3.TransformPosition(vertex.Position, bone.Transform); vertex.Normal = Vector3.TransformNormal(vertex.Normal, bone.Transform); } } } }
private STGenericMesh LoadMesh(ModelBlock mdl, ObjectBlock obj, MeshBlock mesh) { STGenericMesh genericMesh = new STGenericMesh(); genericMesh.Name = obj.Name; var transform = obj.GetTransform(); var meshInfo = obj.MeshData; var ctx = NitroGX.ReadCmds(meshInfo.Data); for (int i = 0; i < ctx.vertices.Count; i++) { STVertex vertex = new STVertex(); vertex.Position = ctx.vertices[i].Position; vertex.Normal = ctx.vertices[i].Normal; vertex.TexCoords = new Vector2[1] { ctx.vertices[i].TexCoord }; vertex.Colors = new Vector4[1] { new Vector4(ctx.vertices[i].Color / 255f, ctx.vertices[i].Alpha / 255f) }; vertex.Position = Vector3.TransformPosition(vertex.Position, transform); genericMesh.Vertices.Add(vertex); } uint[] faces = new uint[ctx.indices.Count]; for (int i = 0; i < ctx.indices.Count; i++) { faces[i] = ctx.indices[i]; } foreach (var poly in mesh.PolyGroups) { var material = mdl.Materials[poly.MaterialIndex]; /* uint[] polyFaces = new uint[poly.FaceCount]; * for (int i = 0; i < poly.FaceCount; i++) { * polyFaces[i] = ctx.indices[poly.FaceStart + i]; * }*/ STGenericMaterial genericMaterial = new STGenericMaterial(); genericMaterial.Name = material.Name; if (material.MaterialBlock.AttributeIndex != -1) { var attribute = mdl.Attributes[material.MaterialBlock.AttributeIndex]; genericMaterial.TextureMaps.Add(new STGenericTextureMap() { Name = attribute.TextureName, Type = STTextureType.Diffuse, }); } genericMesh.PolygonGroups.Add(new STPolygonGroup() { PrimitiveType = STPrimitiveType.Triangles, Material = genericMaterial, Faces = faces.ToList(), }); break; } return(genericMesh); }
static void ReadBufferData(Stream bufferChunk, Dictionary <uint, int> HashToBoneID, List <ChunkTable.ChunkDataEntry> boneHashChunks, List <ModelInfo> models) { int skinningIndex = 0; //Lastly parse the vertex and index buffers using (var reader = new FileReader(bufferChunk, true)) { foreach (var model in models) { for (int i = 0; i < model.Meshes.Count; i++) { var mesh = model.Meshes[i]; //Get our bone hash index lists Dictionary <int, uint> boneIDToHash = new Dictionary <int, uint>(); if (boneHashChunks.Count > skinningIndex) { var boneHashChunk = boneHashChunks[skinningIndex]; uint count = (uint)boneHashChunk.Data.Length / 4; var hashes = boneHashChunk.ReadPrimitive <uint>(count); for (int j = 0; j < count; j++) { boneIDToHash.Add(j, hashes[j]); } } reader.SeekBegin(mesh.MeshHeader.IndexOffset); mesh.Faces = new uint[mesh.IndexCount]; if (mesh.IndexType == 0x8000) { for (int f = 0; f < mesh.IndexCount; f++) { mesh.Faces[f] = reader.ReadByte(); } } else { for (int f = 0; f < mesh.IndexCount; f++) { mesh.Faces[f] = reader.ReadUInt16(); } } uint vertexStride = VertexLoaderExtension.GetStride(mesh.MeshHeader.VertexFormatHash); for (int v = 0; v < mesh.MeshHeader.VertexCount; v++) { reader.SeekBegin(mesh.VertexBufferPointer + (v * vertexStride)); STVertex vertex = reader.ReadVertexLayout(mesh.MeshHeader.VertexFormatHash); for (int j = 0; j < vertex.BoneIndices.Count; j++) { if (HashToBoneID.Count == 0) { break; } uint boneHash = boneIDToHash[vertex.BoneIndices[j]]; //Get the index used from the skeleton's hash list int boneIndex = HashToBoneID[boneHash]; vertex.BoneIndices[j] = boneIndex; } vertex.Position = Vector3.TransformPosition(vertex.Position, model.Transform); //Transform 90 degrees and scale vertex.Position = new Vector3( vertex.Position.X, vertex.Position.Z, -vertex.Position.Y) * ModelWrapper.PreviewScale; vertex.Normal = new Vector3( vertex.Normal.X, vertex.Normal.Z, -vertex.Normal.Y); mesh.Vertices.Add(vertex); } if (mesh.Vertices.Any(x => x.BoneIndices.Count > 0)) { skinningIndex += 1; } } } } }
public static List <ModelInfo> Read(List <ChunkTable.ChunkDataEntry> chunkList, Dictionary <uint, int> HashToBoneID) { List <ModelInfo> models = new List <ModelInfo>(); List <Header> modelHeaders = new List <Header>(); List <MeshInfo> meshes = new List <MeshInfo>(); List <Matrix4> modelMatrices = new List <Matrix4>(); var vertexPointerChunk = chunkList.FirstOrDefault( x => x.ChunkType == ChunkDataType.VertexStartPointers); var bufferChunk = chunkList.FirstOrDefault( x => x.ChunkType == ChunkDataType.MeshBuffers); for (int i = 0; i < chunkList.Count; i++) { var chunk = chunkList[i]; switch (chunk.ChunkType) { case ChunkDataType.ModelInfo: uint numModels = (uint)chunk.Data.Length / MODEL_HEADER_SIZE; modelHeaders = chunk.ReadStructs <Header>(numModels); break; case ChunkDataType.ModelTransform: int numTransforms = (int)chunk.Data.Length / 64; using (var reader = new FileReader(chunk.Data, true)) { for (int j = 0; j < numTransforms; j++) { var values = reader.ReadSingles(16); modelMatrices.Add(new Matrix4( values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8], values[9], values[10], values[11], values[12], values[13], values[14], values[15])); } } break; case ChunkDataType.MeshInfo: uint numMeshes = (uint)chunk.Data.Length / MESH_SIZE; var meshHeaders = chunk.ReadStructs <Mesh>(numMeshes); //Load mesh structs into mesh info //This will store vertex and face data //Read vertex points. These must be parsed by mesh header data using (var reader = new FileReader(vertexPointerChunk.Data, true)) { for (int m = 0; m < numMeshes; m++) { var mesh = new MeshInfo(meshHeaders[m]); meshes.Add(mesh); if (mesh.HasSkinning && reader.BaseStream.Length >= reader.Position + 4) { mesh.SkinningBufferPointer = reader.ReadUInt32(); } if (reader.BaseStream.Length >= reader.Position + 4) { mesh.VertexBufferPointer = reader.ReadUInt32(); } if (reader.BaseStream.Length >= reader.Position + 4) { reader.ReadUInt32(); } if (reader.BaseStream.Length >= reader.Position + 4) { reader.ReadUInt32(); } } } break; } } var materialChunk = chunkList.FirstOrDefault( x => x.ChunkType == ChunkDataType.MaterialData); var materialLookupChunk = chunkList.FirstOrDefault( x => x.ChunkType == ChunkDataType.MaterialLookupTable); MaterialLoaderHelper.ParseMaterials(materialChunk.Data, materialLookupChunk.Data, meshes); int meshIndex = 0; for (int i = 0; i < modelHeaders.Count; i++) { var model = new ModelInfo() { Hash = modelHeaders[i].Hash }; models.Add(model); if (modelMatrices.Count > i) { model.Transform = modelMatrices[i]; } for (int j = 0; j < modelHeaders[i].MeshCount; j++) { model.Meshes.Add(meshes[meshIndex + j]); } meshIndex += (int)modelHeaders[i].MeshCount; } //Get our bone hash index lists Dictionary <int, uint> boneIDToHash = new Dictionary <int, uint>(); var boneStart = chunkList.FirstOrDefault( x => x.ChunkType == ChunkDataType.BoneStart); var boneHashChunk = boneStart != null?boneStart.SubData.FirstOrDefault( x => x.ChunkType == ChunkDataType.BoneHashList) : null; if (boneHashChunk != null) { uint count = (uint)boneHashChunk.Data.Length / 4; var hashes = boneHashChunk.ReadPrimitive <uint>(count); for (int i = 0; i < count; i++) { boneIDToHash.Add(i, hashes[i]); } } //Lastly parse the vertex and index buffers using (var reader = new FileReader(bufferChunk.Data, true)) { foreach (var model in models) { foreach (var mesh in model.Meshes) { reader.SeekBegin(mesh.MeshHeader.IndexOffset); mesh.Faces = new uint[mesh.IndexCount]; if (mesh.IndexType == 0x80) { for (int f = 0; f < mesh.IndexCount; f++) { mesh.Faces[f] = reader.ReadByte(); } } else if (mesh.IndexType == 0x40) { for (int f = 0; f < mesh.IndexCount; f++) { mesh.Faces[f] = reader.ReadUInt32(); } } else { for (int f = 0; f < mesh.IndexCount; f++) { mesh.Faces[f] = reader.ReadUInt16(); } } reader.SeekBegin(mesh.VertexBufferPointer); for (int v = 0; v < mesh.MeshHeader.VertexCount; v++) { STVertex vertex = new STVertex(); vertex.Position = reader.ReadVec3(); float texCoordU = reader.ReadSingle(); vertex.Normal = reader.ReadVec3(); float texCoordV = reader.ReadSingle(); vertex.Tangent = reader.ReadVec4(); vertex.TexCoords = new Vector2[1] { new Vector2(texCoordU, texCoordV) }; vertex.Position = Vector3.TransformPosition(vertex.Position, model.Transform); //Transform 90 degrees and scale vertex.Position = new Vector3( vertex.Position.X, vertex.Position.Z, -vertex.Position.Y) * ModelWrapper.PreviewScale; vertex.Normal = new Vector3( vertex.Normal.X, vertex.Normal.Z, -vertex.Normal.Y); mesh.Vertices.Add(vertex); } if (mesh.HasSkinning && HashToBoneID.Count > 0) { reader.SeekBegin(mesh.SkinningBufferPointer); for (int v = 0; v < mesh.MeshHeader.VertexCount; v++) { byte[] boneIndices = reader.ReadBytes(4); float[] weights = reader.ReadSingles(4); for (int j = 0; j < 4; j++) { if (weights[j] == 0) { break; } //Get the hash indexing the model's bone hash list uint boneHash = boneIDToHash[boneIndices[j]]; //Get the index used from the skeleton's hash list int boneIndex = HashToBoneID[boneHash]; mesh.Vertices[v].BoneIndices.Add(boneIndex); mesh.Vertices[v].BoneWeights.Add(weights[j]); } } } } } } return(models); }