private void ApplyMorphToMeshLod(int lodIndex, MeshAsset mesh) { List <Vector> LodVertices = GetVerticesForLod(lodIndex, mesh); MeshLOD lod = mesh.lods[lodIndex]; int offset = 0; foreach (MeshLodSection section in lod.sections) { if (section.vertices != null) { for (int i = 0; i < section.vertices.Count; i++) { section.vertices[i].position.members[0] = LodVertices[offset].members[0]; section.vertices[i].position.members[1] = LodVertices[offset].members[1]; section.vertices[i].position.members[2] = LodVertices[offset].members[2]; offset++; } } else { // if the lod is not completely loaded, we abort break; } } }
public void LoadVertexData(Stream s, MeshLOD lod) { s.Seek(vertOffset, 0); vertices = new List <Vertex>(); for (int i = 0; i < vertCount; i++) { vertices.Add(new Vertex(s, vertDesc, (int)vertexStride)); } s.Seek(lod.vertexDataSize + indStart * 2, 0); indicies = new List <ushort>(); for (int i = 0; i < triCount * 3; i++) { indicies.Add(Helpers.ReadUShort(s)); } }
/// private byte[] ExportAsObj(MeshAsset mesh, MeshLOD lod) { string[] subMeshNames = new string[lod.sections.Count]; float[][] verts = new float[lod.sections.Count][]; float[][] uvcords = new float[lod.sections.Count][]; ushort[][] indices = new ushort[lod.sections.Count][]; for (int i = 0; i < lod.sections.Count; i++) { subMeshNames[i] = lod.sections[i].matName; verts[i] = GetVerticesPositionsArray(lod.sections[i].vertices); uvcords[i] = GetUVCoordsArray(lod.sections[i].vertices); indices[i] = lod.sections[i].indicies.ToArray(); } return(convertToOBJ(mesh.header.shortName, subMeshNames, verts, uvcords, indices)); }
private void CreateMeshSkinning(SkeletonAsset Skeleton, MeshLOD lod, FBXNode pFbxMesh, FBXNode pSkeletonRoot, FBXScene pScene) { Dictionary <string, List <VertexGroup.VertexWeight> > vg = VertexGroup.GetVertexGroups(Skeleton, lod); CreateMeshSkinning(vg, pFbxMesh, pSkeletonRoot, pScene); }
private FBXNode CreateFbxMesh(MeshLOD lod, FBXScene pScene) { FBXMesh fbxMesh = FBXMesh.Create(pScene, lod.shortName); FBXNode lMeshNode = FBXNode.Create(pScene, lod.shortName); lMeshNode.SetNodeAttribute(fbxMesh); FBXGeometryElementNormal lGeometryElementNormal = fbxMesh.CreateElementNormal(); lGeometryElementNormal.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementBinormal lGeometryElementBiNormal = fbxMesh.CreateElementBinormal(); lGeometryElementBiNormal.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementTangent lGeometryElementTangent = fbxMesh.CreateElementTangent(); lGeometryElementTangent.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementMaterial lMaterialElement = fbxMesh.CreateElementMaterial(); lMaterialElement.SetMappingMode(FBXWrapper.MappingMode.eByPolygon); lMaterialElement.SetReferenceMode(FBXWrapper.ReferenceMode.eIndexToDirect); int verticesCount = lod.GetLODTotalVertCount(); fbxMesh.InitControlPoints(verticesCount); List <FBXGeometryElementUV[]> UVs = new List <FBXGeometryElementUV[]>(); for (int i = 0; i < lod.sections.Count; i++) { UVs.Add(new FBXGeometryElementUV[Vertex.UV_SLOTS]); } int VertexOffset = 0; for (int i = 0; i < lod.sections.Count; i++) { MeshLodSection section = lod.sections[i]; for (int j = 0; j < section.vertices.Count; j++) { FBXVector4 position = new FBXVector4(section.vertices[j].position.members[0] * exportScale, section.vertices[j].position.members[1] * exportScale, section.vertices[j].position.members[2] * exportScale, 0); FBXVector4 normal = new FBXVector4(section.vertices[j].normals.members[0], section.vertices[j].normals.members[1], section.vertices[j].normals.members[2], section.vertices[j].normals.members[3]); fbxMesh.SetControlPoint(VertexOffset + j, position); lGeometryElementNormal.Add(normal); // adding a check on bitangent and tangent as some meshes don't have them... if (section.vertices[j].biTangents.members.Length == 4) { FBXVector4 bitangent = new FBXVector4(section.vertices[j].biTangents.members[0], section.vertices[j].biTangents.members[1], section.vertices[j].biTangents.members[2], section.vertices[j].biTangents.members[3]); lGeometryElementBiNormal.Add(bitangent); } if (section.vertices[j].tangents.members.Length == 4) { FBXVector4 tangent = new FBXVector4(section.vertices[j].tangents.members[0], section.vertices[j].tangents.members[1], section.vertices[j].tangents.members[2], section.vertices[j].tangents.members[3]); lGeometryElementTangent.Add(tangent); } // multiple UVs management for (int uvInd = 0; uvInd < Vertex.UV_SLOTS; uvInd++) { if (section.vertices[j].texCoords[uvInd] != null) { FBXVector4 texCoords = new FBXVector4(section.vertices[j].texCoords[uvInd].members[0], (-section.vertices[j].texCoords[uvInd].members[1] + 1), 0, 0); if (UVs[i][uvInd] == null) { // if the UV layer does not already exist, we create it... UVs[i][uvInd] = fbxMesh.CreateElementUV(section.matName + "_" + uvInd); UVs[i][uvInd].SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); UVs[i][uvInd].SetReferenceMode(FBXWrapper.ReferenceMode.eDirect); // ... and fill it with empty vectors for all previous sections vertices. for (int p = 0; p < VertexOffset + j; p++) { UVs[i][uvInd].Add(new FBXVector4(0, 0, 0, 0)); } } // and now we can add the tex coord of the current vertex we're treating. UVs[i][uvInd].Add(texCoords); } } // since we use direct reference mode for UV, every vertices in the mesh must be present in every UV layer // so for every UV layer created for previous section, we had an empty vector for this vertex. UVs.Where((o, oi) => oi != i).ToList().ForEach(suv => { for (int subuv = 0; subuv < Vertex.UV_SLOTS; subuv++) { if (suv[subuv] != null) { suv[subuv].Add(new FBXVector4(0, 0, 0, 0)); } } } ); } for (int j = 0; j < section.indicies.Count; j++) { if (j % 3 == 0) { fbxMesh.EndPolygon(); fbxMesh.BeginPolygon(i); } fbxMesh.AddPolygon(VertexOffset + section.indicies[j]); } fbxMesh.EndPolygon(); VertexOffset = VertexOffset + section.vertices.Count; lMeshNode.AddMaterial(pScene, section.matName); } return(lMeshNode); }
public static Dictionary <string, List <VertexWeight> > GetVertexGroups(SkeletonAsset skeleton, MeshLOD lod) { var VertexGroupDict = new Dictionary <string, List <VertexWeight> >(); int VertCount = 0; foreach (var section in lod.sections) { VertCount = GetVertexGroups(skeleton, section, VertCount, ref VertexGroupDict); } return(VertexGroupDict); }
// export given LOD to psk private byte[] ExportSkinnedMeshToPsk(SkeletonAsset skeleton, MeshLOD LOD, float OverrideScale = 1.0f) { PSKFile Psk = new PSKFile(); Psk.points = new List <PSKFile.PSKPoint>(); Psk.edges = new List <PSKFile.PSKEdge>(); Psk.materials = new List <PSKFile.PSKMaterial>(); Psk.bones = new List <PSKFile.PSKBone>(); Psk.faces = new List <PSKFile.PSKFace>(); Psk.weights = new List <PSKFile.PSKWeight>(); /* No skeleton defined still */ if (skeleton != null) { for (int i = 0; i < skeleton.Bones.Count; i++) { PSKFile.PSKBone Bone = new PSKFile.PSKBone(); Bone.name = skeleton.Bones[i].Name; Bone.childs = skeleton.Bones[i].Children.Count; Bone.parent = (skeleton.Bones[i].ParentIndex == -1) ? 0 : skeleton.Bones[i].ParentIndex; Bone.index = i; Bone.location = new PSKFile.PSKPoint(ConvertVector3ToPsk(skeleton.Bones[i].Location) * OverrideScale); Bone.rotation = new PSKFile.PSKQuad(0, 0, 0, 0); float[][] RotMatrix = new float[4][]; RotMatrix[0] = new float[4]; RotMatrix[1] = new float[4]; RotMatrix[2] = new float[4]; RotMatrix[3] = new float[4]; RotMatrix[0][0] = skeleton.Bones[i].Right.members[0]; RotMatrix[0][1] = skeleton.Bones[i].Right.members[1]; RotMatrix[0][2] = skeleton.Bones[i].Right.members[2]; RotMatrix[0][3] = 0.0f; RotMatrix[1][0] = skeleton.Bones[i].Up.members[0]; RotMatrix[1][1] = skeleton.Bones[i].Up.members[1]; RotMatrix[1][2] = skeleton.Bones[i].Up.members[2]; RotMatrix[1][3] = 0.0f; RotMatrix[2][0] = skeleton.Bones[i].Forward.members[0]; RotMatrix[2][1] = skeleton.Bones[i].Forward.members[1]; RotMatrix[2][2] = skeleton.Bones[i].Forward.members[2]; RotMatrix[2][3] = 0.0f; RotMatrix[3][0] = 0.0f; RotMatrix[3][1] = 0.0f; RotMatrix[3][2] = 0.0f; RotMatrix[3][3] = 1.0f; Vector Quat = new Vector(new float[4]); float tr = RotMatrix[0][0] + RotMatrix[1][1] + RotMatrix[2][2]; float s; if (tr > 0.0f) { float InvS = 1.0f / (float)Math.Sqrt(tr + 1.0f); Quat.members[3] = 0.5f * (1.0f / InvS); s = 0.5f * InvS; Quat.members[0] = (RotMatrix[1][2] - RotMatrix[2][1]) * s; Quat.members[1] = (RotMatrix[2][0] - RotMatrix[0][2]) * s; Quat.members[2] = (RotMatrix[0][1] - RotMatrix[1][0]) * s; } else { int m = 0; if (RotMatrix[1][1] > RotMatrix[0][0]) { m = 1; } if (RotMatrix[2][2] > RotMatrix[m][m]) { m = 2; } int[] nxt = new int[] { 1, 2, 0 }; int j = nxt[m]; int k = nxt[j]; s = RotMatrix[m][m] - RotMatrix[j][j] - RotMatrix[k][k] + 1.0f; float InvS = 1.0f / (float)Math.Sqrt(s); float[] qt = new float[4]; qt[m] = 0.5f * (1.0f / InvS); s = 0.5f * InvS; qt[3] = (RotMatrix[j][k] - RotMatrix[k][j]) * s; qt[j] = (RotMatrix[m][j] + RotMatrix[j][m]) * s; qt[k] = (RotMatrix[m][k] + RotMatrix[k][m]) * s; Quat.members[0] = qt[0]; Quat.members[1] = qt[1]; Quat.members[2] = qt[2]; Quat.members[3] = qt[3]; } Bone.rotation = new PSKFile.PSKQuad(ConvertVector4ToPsk(Quat)); Psk.bones.Add(Bone); } } int offset = 0; int matIdx = 0; for (int bufIdx = 0; bufIdx < LOD.sections.Count; bufIdx++) { MeshLodSection MeshBuffer = LOD.sections[bufIdx]; for (int i = 0; i < MeshBuffer.vertices.Count; i++) { if (MeshBuffer.vertices[i].position.members.Length != 3) { MeshBuffer.vertices[i].position.members = new float[3]; } if (MeshBuffer.vertices[i].texCoords.members.Length != 2) { MeshBuffer.vertices[i].texCoords.members = new float[2]; } Vector p = new Vector(MeshBuffer.vertices[i].position.members[0], MeshBuffer.vertices[i].position.members[1], MeshBuffer.vertices[i].position.members[2]); Psk.points.Add(new PSKFile.PSKPoint(ConvertVector3ToPsk(p))); Vector tc = new Vector(MeshBuffer.vertices[i].texCoords.members[0], MeshBuffer.vertices[i].texCoords.members[1]); Psk.edges.Add(new PSKFile.PSKEdge((ushort)(offset + i), ConvertVector2ToPsk(tc), (byte)matIdx)); if (MeshBuffer.vertices[i].boneWeights != null) { for (int x = 0; x < 4; x++) { float Weight = MeshBuffer.vertices[i].boneWeights[x]; // only add meaningful weights if (Weight != 0.0f) { int BoneIndex = MeshBuffer.vertices[i].boneIndices[x]; int SubObjectBoneIndex = MeshBuffer.boneIndices[BoneIndex]; Psk.weights.Add(new PSKFile.PSKWeight( Weight, (int)(offset + i), SubObjectBoneIndex )); } } } } // reverse indices order before building faces: necessary for correct normal building since all points have been mirrored along z-axis. // if this is not done, all normals are flipped inside. if (Reverse) { MeshBuffer.indicies.Reverse(); } for (int fi = 0; fi < MeshBuffer.indicies.Count; fi++) { if (fi % 3 == 0) { Psk.faces.Add(new PSKFile.PSKFace( (int)(offset + MeshBuffer.indicies[fi]), (int)(offset + MeshBuffer.indicies[fi + 1]), (int)(offset + MeshBuffer.indicies[fi + 2]), (byte)matIdx) ); } } Psk.materials.Add(new PSKFile.PSKMaterial(LOD.sections[bufIdx].matName, matIdx)); offset += (int)LOD.sections[bufIdx].vertCount; matIdx++; } return(Psk.SaveToMemory().ToArray()); }
// export given LOD to psk private byte[] ExportSkinnedMeshToPsk(SkeletonAsset skeleton, MeshLOD LOD, float OverrideScale = 1.0f) { PSKFile Psk = new PSKFile(); Psk.points = new List <PSKFile.PSKPoint>(); Psk.edges = new List <PSKFile.PSKEdge>(); Psk.materials = new List <PSKFile.PSKMaterial>(); Psk.bones = new List <PSKFile.PSKBone>(); Psk.faces = new List <PSKFile.PSKFace>(); Psk.weights = new List <PSKFile.PSKWeight>(); // create skeleton (only if mesh is skinned mesh) if (LOD.type == MeshType.MeshType_Skinned) { Psk.bones = CreatePskSkeleton(skeleton, OverrideScale); } // create mesh int offset = 0; int matIdx = 0; for (int bufIdx = 0; bufIdx < LOD.sections.Count; bufIdx++) { MeshLodSection MeshBuffer = LOD.sections[bufIdx]; for (int i = 0; i < MeshBuffer.vertices.Count; i++) { // vertex position if (MeshBuffer.vertices[i].position.members.Length != 3) { MeshBuffer.vertices[i].position.members = new float[3]; } Vector p = new Vector(MeshBuffer.vertices[i].position.members[0] * OverrideScale, MeshBuffer.vertices[i].position.members[1] * OverrideScale, MeshBuffer.vertices[i].position.members[2] * OverrideScale); Psk.points.Add(new PSKFile.PSKPoint(ConvertVector3ToPsk(p))); // vertex uv // supports only first uv for the time being // TODO support for multiple UVs if (MeshBuffer.vertices[i].texCoords[0] == null) { MeshBuffer.vertices[i].texCoords[0] = new Vector(new float[2]); } if (MeshBuffer.vertices[i].texCoords[0].members.Length != 2) { MeshBuffer.vertices[i].texCoords[0].members = new float[2]; } Vector tc = new Vector(MeshBuffer.vertices[i].texCoords[0].members[0], MeshBuffer.vertices[i].texCoords[0].members[1]); Psk.edges.Add(new PSKFile.PSKEdge((ushort)(offset + i), ConvertVector2ToPsk(tc), (byte)matIdx)); // bones weights if (MeshBuffer.vertices[i].boneWeights != null) { for (int x = 0; x < 4; x++) { float Weight = MeshBuffer.vertices[i].boneWeights[x]; // only add meaningful weights if (Weight != 0.0f) { int BoneIndex = MeshBuffer.vertices[i].boneIndices[x]; int SubObjectBoneIndex = MeshBuffer.boneIndices[BoneIndex]; Psk.weights.Add(new PSKFile.PSKWeight( Weight, (int)(offset + i), SubObjectBoneIndex )); } } } } // reverse indices order before building faces: necessary for correct normal building since all points have been mirrored along z-axis. // if this is not done, all normals are flipped inside. if (Reverse) { MeshBuffer.indicies.Reverse(); } for (int fi = 0; fi < MeshBuffer.indicies.Count; fi++) { if (fi % 3 == 0) { Psk.faces.Add(new PSKFile.PSKFace( (int)(offset + MeshBuffer.indicies[fi]), (int)(offset + MeshBuffer.indicies[fi + 1]), (int)(offset + MeshBuffer.indicies[fi + 2]), (byte)matIdx) ); } } Psk.materials.Add(new PSKFile.PSKMaterial(LOD.sections[bufIdx].matName, matIdx)); offset += (int)LOD.sections[bufIdx].vertCount; matIdx++; } return(Psk.SaveToMemory().ToArray()); }
private FBXNode CreateFbxMesh(MeshLOD lod, FBXScene pScene) { FBXMesh fbxMesh = FBXMesh.Create(pScene, lod.shortName); FBXNode lMeshNode = FBXNode.Create(pScene, lod.shortName); lMeshNode.SetNodeAttribute(fbxMesh); FBXGeometryElementNormal lGeometryElementNormal = fbxMesh.CreateElementNormal(); lGeometryElementNormal.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementBinormal lGeometryElementBiNormal = fbxMesh.CreateElementBinormal(); lGeometryElementBiNormal.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementTangent lGeometryElementTangent = fbxMesh.CreateElementTangent(); lGeometryElementTangent.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); FBXGeometryElementMaterial lMaterialElement = fbxMesh.CreateElementMaterial(); lMaterialElement.SetMappingMode(FBXWrapper.MappingMode.eByPolygon); lMaterialElement.SetReferenceMode(FBXWrapper.ReferenceMode.eIndexToDirect); int verticesCount = lod.GetLODTotalVertCount(); fbxMesh.InitControlPoints(verticesCount); List <FBXGeometryElementUV> UVs = new List <FBXGeometryElementUV>(); for (int i = 0; i < lod.sections.Count; i++) { MeshLodSection section = lod.sections[i]; FBXGeometryElementUV lUVDiffuseElement = fbxMesh.CreateElementUV(section.matName); lUVDiffuseElement.SetMappingMode(FBXWrapper.MappingMode.eByControlPoint); lUVDiffuseElement.SetReferenceMode(FBXWrapper.ReferenceMode.eDirect); UVs.Add(lUVDiffuseElement); } int VertexOffset = 0; for (int i = 0; i < lod.sections.Count; i++) { MeshLodSection section = lod.sections[i]; for (int j = 0; j < section.vertices.Count; j++) { FBXVector4 position = new FBXVector4(section.vertices[j].position.members[0] * exportScale, section.vertices[j].position.members[1] * exportScale, section.vertices[j].position.members[2] * exportScale, 0); FBXVector4 normal = new FBXVector4(section.vertices[j].normals.members[0], section.vertices[j].normals.members[1], section.vertices[j].normals.members[2], section.vertices[j].normals.members[3]); FBXVector4 textCoords = new FBXVector4(section.vertices[j].texCoords.members[0], (-section.vertices[j].texCoords.members[1] + 1), 0, 0); FBXVector4 bitangent = new FBXVector4(section.vertices[j].biTangents.members[0], section.vertices[j].biTangents.members[1], section.vertices[j].biTangents.members[2], section.vertices[j].biTangents.members[3]); FBXVector4 tangent = new FBXVector4(section.vertices[j].tangents.members[0], section.vertices[j].tangents.members[1], section.vertices[j].tangents.members[2], section.vertices[j].tangents.members[3]); fbxMesh.SetControlPoint(VertexOffset + j, position); lGeometryElementNormal.Add(normal); lGeometryElementBiNormal.Add(bitangent); lGeometryElementTangent.Add(tangent); int uvI = 0; foreach (FBXGeometryElementUV uv in UVs) { if (uvI == i) { uv.Add(textCoords); } else { uv.Add(new FBXVector4(0, 0, 0, 0)); } uvI++; } } for (int j = 0; j < section.indicies.Count; j++) { if (j % 3 == 0) { fbxMesh.EndPolygon(); fbxMesh.BeginPolygon(i); } fbxMesh.AddPolygon(VertexOffset + section.indicies[j]); } fbxMesh.EndPolygon(); VertexOffset = VertexOffset + section.vertices.Count; lMeshNode.AddMaterial(pScene, section.matName); } return(lMeshNode); }